【python】Threading快速使用和线程锁的理解及.join()用法详说

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lzy98/article/details/78815031

0X0:在开始之前先理解一下threading的意义,我们知道写一个程序,之后程序运行完毕,得到想要的结果。这就是我对一个软件的理解。
那么有时候就出现了一个问题,如果这个程序在运行过程中要实现多个功能,即先运行第一个功能,同时运行第二个功能,最后运行第三个功能,python为我们提供threading库来为我们服务。

0X1:如果你对我刚才说的运行一二三个程序没有理解,就这么说吧,你的python程序中有三个函数,你要先运行第一个同时运行第二个,最后运行第三个。当然你可以直接一个一个的启动,但是这样会浪费不少的时间,而且当其中一个函数出错了你还要在源代码添加except来捕获异常来处理,所以得不偿失,合理的使用threading就能避免这个问题。

1X1:下面我通过代码来展示threading的使用,先看第一个,第一个是threading的常规使用办法,我会在源代码添加注释方便大家阅读

# -*- coding: utf-8 -*-
"""
__author__ = 'Langziyanqin'
__QQ__ = '982722261'
              ┏┓      ┏┓
            ┏┛┻━━━┛┻┓
            ┃      ☃      ┃
            ┃  ┳┛  ┗┳  ┃
            ┃      ┻      ┃
            ┗━┓      ┏━┛
                ┃      ┗━━━┓
                ┃  神兽保佑    ┣┓
                ┃ 永无BUG!   ┏┛
                ┗┓┓┏━┳┓┏┛
                  ┃┫┫  ┃┫┫
                  ┗┻┛  ┗┻┛
"""
import sys
import threading
import Queue
import time
reload(sys)
sys.setdefaultencoding('utf-8')
q = Queue.Queue()
def loop():   #定义一个要循环的函数,当然后面肯定会定义好几个函数
    print 'thread %s is running...' % threading.current_thread().name
    #threading.current_thread().name就是当前线程的名字  可以在第35行中看到  可以自定义子线程的名字
    n = 0
    while n < 10:
        n = n + 1
        print '%s >>> %s' % (threading.current_thread().name, n)
        #输出当前线程名字  和循环的参数n
    print 'thread %s ended.' % threading.current_thread().name
print 'thread %s is running...' % threading.current_thread().name

#下面的一部分就是threading的核心用法
t = threading.Thread(target=loop) #包括target name args 之类的 一般我只用targer=你定义的函数名
#t = threading.Thread(target=loop, name='当前线程为:')
t.start() #开始
t.join()  #关于join的相关信息我会在后面的代码详说
print 'thread %s ended.' % threading.current_thread().name

运行结果

F:\Python27\python.exe "E:/python27/python study/threading1.py"
thread MainThread is running...
thread Thread-1 is running...
Thread-1 >>> 1
Thread-1 >>> 2
Thread-1 >>> 3
Thread-1 >>> 4
Thread-1 >>> 5
Thread-1 >>> 6
Thread-1 >>> 7
Thread-1 >>> 8
Thread-1 >>> 9
Thread-1 >>> 10
thread Thread-1 ended.
thread MainThread ended.

进程已结束,退出代码0

你也可以在#t = threading.Thread(target=loop, name=’当前线程为:’) 设置成自己的名字
当然你要先把注释符去掉,并且在上一行加入注释符,这样只是让大家更直观的看到使用方法。

1X2:既然常规的使用方法已说完,接下来说说进阶的,如果一个程序有两个函数要运行,常规的加载使用办法为

# -*- coding: utf-8 -*-
"""
__author__ = 'Langziyanqin'
__QQ__ = '982722261'
              ┏┓      ┏┓
            ┏┛┻━━━┛┻┓
            ┃      ☃      ┃
            ┃  ┳┛  ┗┳  ┃
            ┃      ┻      ┃
            ┗━┓      ┏━┛
                ┃      ┗━━━┓
                ┃  神兽保佑    ┣┓
                ┃ 永无BUG!   ┏┛
                ┗┓┓┏━┳┓┏┛
                  ┃┫┫  ┃┫┫
                  ┗┻┛  ┗┻┛
"""
import sys
import threading
import time
import Queue
reload(sys)
sys.setdefaultencoding('utf-8')
t00 = time.time()
def cs1():
    time0 = time.time()
    for x in range(5):
        print x + time.time()-time0 #+ threading.current_thread().name
        print threading.current_thread().name


def cs2():
    for x1 in range(6,9):
        print x1
        time.sleep(0.5)
        print threading.current_thread().name


threads=[]

t1 = threading.Thread(target=cs1)#,name='当先现场:')
t2 = threading.Thread(target=cs2)
threads.append(t1)
threads.append(t2)
for x in threads:
    x.start()
#x.join()   #线程不堵塞  但是会出现不匀称的表现  并且会修改不同线程中的变量
    x.join()  #线程堵塞 先运行第一个在运行第二个
print 'use time.{}'.format(time.time()-t00)

其实就是新建一个列表,把两个进程加载进去,然后迭代使用一遍,关于join,大家看下注释就能明白,join在不同的地方作用也不同,那么我们看看下面这样会使用多少时间呢

for x in threads:
    x.start()
    x.join()  #线程堵塞 先运行第一个在运行第二个
print 'use time.{}'.format(time.time()-t00)

运行结果

F:\Python27\python.exe "E:/python27/python study/threading2.py"
0.0
Thread-1
1.0
Thread-1
2.0
Thread-1
3.0
Thread-1
4.0
Thread-1
6
Thread-2
7
Thread-2
8
Thread-2
use time.1.50099992752

进程已结束,退出代码0

可以看到是先把第一个函数运行完毕在运行第二个函数那么试一下下面使用的时间

for x in threads:
    x.start()
x.join()   #线程不堵塞  但是会出现不匀称的表现  并且会修改不同线程中的变量
print 'use time.{}'.format(time.time()-t00)
F:\Python27\python.exe "E:/python27/python study/threading2.py"
0.0
Thread-1
1.0
Thread-16

2.0
Thread-1
3.0
Thread-1
4.0
Thread-1
Thread-2
7
Thread-2
8
Thread-2
use time.1.50200009346

进程已结束,退出代码0

这里可以明显直观的看到,输出的结果混乱(同时运行,同时输出)两个函数是同时运行的。而且用的时间一样,如果把函数其中的time.sleep(0.5)去掉之后看看效果

for x in threads:
    x.start()
#x.join()   #线程不堵塞  但是会出现不匀称的表现  并且会修改不同线程中的变量
    x.join()  #线程堵塞 先运行第一个在运行第二个
print 'use time.{}'.format(time.time()-t00)
F:\Python27\python.exe "E:/python27/python study/threading2.py"
0.0
Thread-1
1.00100016594
Thread-1
2.00100016594
Thread-1
3.00100016594
Thread-1
4.00100016594
Thread-1
6
Thread-2
7
Thread-2
8
Thread-2
use time.0.00100016593933

进程已结束,退出代码0

第二个

for x in threads:
    x.start()
x.join()   #线程不堵塞  但是会出现不匀称的表现  并且会修改不同线程中的变量
    #x.join()  #线程堵塞 先运行第一个在运行第二个
print 'use time.{}'.format(time.time()-t00)
F:\Python27\python.exe "E:/python27/python study/threading2.py"
0.0
Thread-1
1.0
Thread-16

2.00099992752Thread-2

Thread-17

3.00099992752
 Thread-1Thread-2

4.000999927528

Thread-1Thread-2

use time.0.000999927520752

进程已结束,退出代码0

1X3:可以看到第二个用的时间少一些,因为只是轻微的计算量所以时间上看不出什么太大的区别,当你的函数更加复杂的时候,就能看到这两者的区别了。
大家有没有发现,我在两个函数中第一个函数迭代的变量是x 第二个迭代的变量是x1,这是为什么呢?
因为啊,主线程中两个子线程都是共享变量的,所以如果两个函数迭代的都是x,那么会出现什么效果呢?
看看演示:
修改源代码,统一变量x:

# -*- coding: utf-8 -*-
"""
__author__ = 'Langziyanqin'
__QQ__ = '982722261'
              ┏┓      ┏┓
            ┏┛┻━━━┛┻┓
            ┃      ☃      ┃
            ┃  ┳┛  ┗┳  ┃
            ┃      ┻      ┃
            ┗━┓      ┏━┛
                ┃      ┗━━━┓
                ┃  神兽保佑    ┣┓
                ┃ 永无BUG!   ┏┛
                ┗┓┓┏━┳┓┏┛
                  ┃┫┫  ┃┫┫
                  ┗┻┛  ┗┻┛
"""
import sys
import threading
import time
import Queue
reload(sys)
sys.setdefaultencoding('utf-8')
t00 = time.time()
def cs1():
    time0 = time.time()
    for x in range(9):
        print x + time.time()-time0 #+ threading.current_thread().name
        print threading.current_thread().name


def cs2():
    for x in range(6,9):
        print x
        #time.sleep(0.5)
        print threading.current_thread().name


threads=[]

t1 = threading.Thread(target=cs1)#,name='当先现场:')
t2 = threading.Thread(target=cs2)
threads.append(t1)
threads.append(t2)
for x in threads:
    x.start()
x.join()   #线程不堵塞  但是会出现不匀称的表现  并且会修改不同线程中的变量
    #x.join()  #线程堵塞 先运行第一个在运行第二个
print 'use time.{}'.format(time.time()-t00)

运行结果:

F:\Python27\python.exe "E:/python27/python study/threading2.py"
0.0
Thread-1
1.0
Thread-1
2.0
Thread-1
3.0
Thread-1
4.0
Thread-1
5.0
Thread-1
 6.06

Thread-1Thread-2

7.07

Thread-1Thread-2

8.08

Thread-1Thread-2

use time.0.000999927520752

进程已结束,退出代码0

可以看到同时运行的时候变量被改变了。
接下来我要说的就是threading的线程锁,防止在运行过程中第一个子线程改变第二个子线程中函数的变量。
threading为我们提供了lock的方法。

1X4:使用方法其实很简单,大家看一看下面的代码就这怎么用了。

# -*- coding: utf-8 -*-
"""
__author__ = 'Langziyanqin'
__QQ__ = '982722261'
              ┏┓      ┏┓
            ┏┛┻━━━┛┻┓
            ┃      ☃      ┃
            ┃  ┳┛  ┗┳  ┃
            ┃      ┻      ┃
            ┗━┓      ┏━┛
                ┃      ┗━━━┓
                ┃  神兽保佑    ┣┓
                ┃ 永无BUG!   ┏┛
                ┗┓┓┏━┳┓┏┛
                  ┃┫┫  ┃┫┫
                  ┗┻┛  ┗┻┛
"""
import sys
import threading
import time
reload(sys)
sys.setdefaultencoding('utf-8')
l = threading.Lock()
t00 = time.time()
def cs1():
    l.acquire()
    time0 = time.time()
    for x in range(5):
        print x + time.time()-time0 #+ threading.current_thread().name
        print threading.current_thread().name
    #finally:
    l.release()


def cs2():
    l.acquire()
    for x in range(6,9):
        print x
        #time.sleep(0.5)
        print threading.current_thread().name
    l.release()


threads=[]

t1 = threading.Thread(target=cs1)#,name='当先现场:')
t2 = threading.Thread(target=cs2)
threads.append(t1)
threads.append(t2)
for x in threads:
    x.start()
x.join()   #线程不堵塞  但是会出现不匀称的表现  并且会修改不同线程中的变量
print 'use time{}'.format(time.time()-t00)

运行结果:

F:\Python27\python.exe "E:/python27/python study/threading3.py"
0.0
Thread-1
1.0
Thread-1
2.0
Thread-1
3.0
Thread-1
4.0
Thread-1
6
Thread-2
7
Thread-2
8
Thread-2
use time0.0

进程已结束,退出代码0

…….

猜你喜欢

转载自blog.csdn.net/lzy98/article/details/78815031