Python 多線程Threading

jopen 8年前發布 | 46K 次閱讀 Python開發

不喜歡廢話,先上今天的代碼!

#-*- coding:utf-8 -*-
import threading
class MyThreading(threading.Thread):
    def __init__(self,num):
        threading.Thread.__init__(self)
        self.num  =  num
    def run(self):
        print self.num
        
        
t = MyThreading(100)
t.start()
print t.isAlive()

乍一看,很簡單的threading代碼。首先我們繼承了Thread類,在子類里初始化后又重寫了run方法。最后我們實例化MyThreading子類,然后打印我們的num參數。最后再打印線程執行狀態。

初學者一看,絕對分為2派:1、支持說先打印num參數,然后才打印線程狀態。 2、拍胸脯保證先打印線程狀態再打印num參數;

 

其實結果出人預料:

結果1:

C:\Python27\python.exe D:/ProjectSpace/thread-example.py
100True
Process finished with exit code 0

 

結果2:

C:\Python27\python.exe D:/ProjectSpace/thread-example.py
True100
Process finished with exit code 0

 

 

吃驚嗎?也許每次運行結果可能會有幾次相同,但是在運行10次內,至少會有1-4次不同結果。

 

答案:線程的執行將是無序的

 

帶著上面的問題,我們繼續看下面一個例子:

 

#-*- coding:utf-8 -*-
import threading,time
class MyThreading(threading.Thread):
    def __init__(self,num):
        threading.Thread.__init__(self)
        self.num  =  num
    def run(self):
        time.sleep(10)
        print self.num
        
def function1():
    t1.start()
    time.sleep(1)
    print "t1 thread was Destruction "
    
def function2():
    t2.start()
    time.sleep(1)
    print "t2 thread was Destruction "
    
    
t1 = MyThreading(10)
t2 = MyThreading(20)
t2.setDaemon(True)
function1()
function2()

 

當你多次運行代碼的時候,大概你能看到如下結果:

C:\Python27\python.exe D:/ProjectSpace/thread-example.py
t1 thread was Destruction 
t2 thread was Destruction 
10
Process finished with exit code 0

 

讓我們看看單步調試運行下的結果是怎么樣的:

C:\Python27\python.exe "C:\Program Files (x86)\JetBrains\PyCharm 5.0.3\helpers\pydev\pydevd.py" --multiproc --qt-support --client 127.0.0.1 --port 62267 --file D:/ProjectSpace/thread-example.py
Connected to pydev debugger (build 143.1559)
10
t1 thread was Destruction 
20
t2 thread was Destruction
Process finished with exit code 0

 

是的, 你沒有看錯! 出現不同的結果的原因是:

Threadclass.setDeamon方法指定了一個線程為主線程;而主線程的作用是當它要退出時會先檢查子進程是否完成,如果未完成則繼續等待,完成則退出。

 

這也是為什么我們在Debug模式時走的是邏輯上的方法,而實際上在運行時的結果卻如上所述。

 

那么問題來了!:我們如何保證程序的順序執行呢?

 

為了保證線程的執行順序或者說是為了保證一致性,針對線程的操作引入了同步的概念。而針對同步最好的辦法也就是對操作進行加鎖了。(加鎖讓我想起了MySQL的鎖  -  _ -)

請繼續看下面的2個例子:

 

例1:

#-*- coding:utf-8 -*-
import threading,time
####繼承Thread類
class MyThreading(threading.Thread):
    def __init__(self,name):
        ####初始化父類
        threading.Thread.__init__(self,name=name)
    def run(self):
        ####引入全局變量
        global x
        ####給操作加鎖
        lock.acquire()
        for i in range(3):
            x = x + 1
        time.sleep(3)
        print x
        ####操作完成并解鎖
        lock.release()
####實例化一個鎖的類
lock = threading.RLock()
####定義一個空的線程類的列表
tl = []
####實例化10個類,并且將類添加到tl這個類列表里
for i in range(10):
    t = MyThreading(str(i))
    tl.append(t)
####初始化全局
x = 0
####逐個執行所有已經實例化的線程
for i in tl:
    i.start()

 輸出結果如下

C:\Python27\python.exe D:/ProjectSpace/thread-example.py
3
6
9
12
15
18
21
24
27
30
Process finished with exit code 0

 

代碼很簡單,首先通過一個循環實例化10個類放進一個列表內,再從列表內遍歷出來運行。 因為執行了加鎖——》釋放這個步驟。如果在time.sleep()時間內未到,release無法執行。所以我們能控制程序的順序。

 

例2:

#-*- coding:utf-8 -*-
import threading,time
####繼承Thread類
class MyThreading(threading.Thread):
    def __init__(self,name):
        ####初始化父類
        threading.Thread.__init__(self,name=name)
    def run(self):
        ####引入全局變量
        global x
        ####給操作加鎖
        #lock.acquire()
        for i in range(3):
            x = x + 1
        time.sleep(3)
        print x
        ####操作完成解鎖
        #lock.release()
####實例化一個鎖的類
#lock = threading.RLock()
####定義一個空的線程類的列表
tl = []
####實例化10個類,并且將類添加到tl這個類列表里
for i in range(10):
    t = MyThreading(str(i))
    tl.append(t)
####初始化全局
x = 0
####逐個執行所有已經實例化的線程
for i in tl:
    i.start()

 輸出結果如下

C:\Python27\python.exe D:/ProjectSpace/thread-example.py
30
30
30
30
30
30
30
30
30
30
Process finished with exit code 0

 

 同例1一樣,程序從列表拿出實例化的類運行;但是因為沒對run方法進行加鎖,所以線程運行到time.sleep()時不會等待就啟動第二個....第三個.....直到最后一個。

 而當run方法全部運行完畢后,并且計算出全局變量X的最終值,time.sleep時間到了;這時候X已經為30,所以每個X輸出的值都是30了。

 

一個簡單的Threading函數同步實例就說到這里! 下次見~~~   (— 3 —)

來自: http://my.oschina.net/CandyMi/blog/599165

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!