Python 多線程Threading (一)

不喜歡廢話,先上今天的代碼!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參數。最後再打印線程執行狀態。app

初學者一看,絕對分爲2派:一、支持說先打印num參數,而後纔打印線程狀態。 二、拍胸脯保證先打印線程狀態再打印num參數;函數

 

其實結果出人預料:ui

結果1:spa

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次不一樣結果。debug

 

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

 

帶着上面的問題,咱們繼續看下面一個例子:code

 

#-*- 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 —)

相關文章
相關標籤/搜索