1. 程式人生 > >【python】Threading快速使用和執行緒鎖的理解及.join()用法詳說

【python】Threading快速使用和執行緒鎖的理解及.join()用法詳說

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

…….