python中的執行緒

任平生78發表於2018-02-09

1.執行緒的建立

1.1 通過thread類直接建立

    import threading
    import time
    
    def foo(n):
        time.sleep(n)
        print("foo func:",n)
    
    def bar(n):
        time.sleep(n)
        print("bar func:",n)
    
    s1=time.time()
    
    #建立一個執行緒例項t1,foo為這個執行緒要執行的函式
    t1=threading.Thread(target=foo,args=(3,))
    t1.start()    #啟動執行緒t1
    
    #建立一個執行緒例項t2,bar為這個執行緒要執行的函式
    t2=threading.Thread(target=bar,args=(5,))
    t2.start()    #啟動執行緒t2
    
    print("ending")
    
    s2=time.time()
    
    print("cost time:",s2-s1)

在這段程式裡,一個函式會先休眠幾秒鐘,然後再列印一句話,第二個函式也是先休眠幾秒鐘,然後列印一句話。

接著程式會例項化兩個執行緒,並呼叫兩個函式來執行,最後會列印程式問總共執行了多少時間

程式執行結果如下:

ending
cost time: 0.002000093460083008
foo func: 3
bar func: 5

程式會先執行父執行緒,列印"ending",然後列印程式執行父執行緒的時間,最後才會執行子執行緒

1.2 通過thread類來繼承式建立

    import threading
    import time
    
    # 定義MyThread類,其繼承自threading.Thread這個父類
    class MyThread(threading.Thread): 
    
        def __init__(self):
            threading.Thread.__init__(self)
    
        def run(self):
            print("ok")
            time.sleep(2)
            print("end t1")
    
    # 對類進行例項化
    t1=MyThread()
    
    # 啟動執行緒
    t1.start()
    print("ending")

2. Thread類的一些常用方法

2.1 join():在子執行緒完成之前,主執行緒將一直被阻塞

執行緒的join方法必須在子執行緒的start方法之後定義

在第一個例子中加入兩行程式碼,如下:

    import threading
    import time
    
    
    def foo(n):
        time.sleep(n)
        print("foo func:",n)
    
    def bar(n):
        time.sleep(n)
        print("bar func:",n)
    
    s1=time.time()
    t1=threading.Thread(target=foo,args=(3,))
    t1.start()
    
    t2=threading.Thread(target=bar,args=(5,))
    t2.start()
    
    t1.join()       # 阻塞t1執行緒
    t2.join()       # 阻塞t2執行緒
    
    print("ending")
    s2=time.time()
    
    print("cost time:",s2-s1)

再次執行程式,執行結果如下:

foo func: 3
bar func: 5
ending
cost time: 5.002285957336426

程式執行到子執行緒t1中的foo方法時會睡眠3秒鐘,與此同時,子執行緒t2也在睡眠

等到子執行緒t1睡眠完成後,開始列印foo函式中的print語句,然後子執行緒t1執行完成

2秒鐘之後,子執行緒t2睡眠完成,開始列印bar函式中的print語句,然後子執行緒t2也執行完成。

而在這之前,主執行緒一直處於阻塞狀態。等到子執行緒執行完成之後主執行緒才會執行

2.2 setDeamon(True)

setDaemon方法作用是將程式宣告為守護執行緒,必須在`start()`方法呼叫之前,

如果不設定為守護執行緒,程式會被無限掛起

在程式執行過程中,執行一個主執行緒,主執行緒又建立一個子執行緒時,主執行緒和子執行緒會分別執行。

當主執行緒執行完成時,會檢驗子執行緒是否執行完成,如果子執行緒執行完成,則主執行緒會等待子執行緒完成後再退出。

但是有的時候只要主執行緒執行完成之後,不管子執行緒是否執行完成,都和主執行緒一起退出,這個就需要呼叫setDeamon方法了。

拿第一個例子來說吧,現在我想讓子執行緒t1和t2隨同主執行緒關閉,程式碼如下:

    import threading
    import time
    
    def foo(n):
        print("foo start")
        time.sleep(n)
        print("foo end...")
    
    def bar(n):
        print("bar start")
        time.sleep(n)
        print("bar end...")
    
    s1 = time.time()
    t1 = threading.Thread(target=foo, args=(3,))
    t1.setDaemon(True)
    t1.start()
    
    t2 = threading.Thread(target=bar, args=(5,))
    t2.setDaemon(True)
    t2.start()
    
    print("ending")
    s2 = time.time()
    
    print("cost time:", s2 - s1)

程式執行結果如下 :

foo start
bar start
ending
cost time: 0.003000020980834961

可以看到,把t1和t2都宣告為守護執行緒後,程式自上而下執行,先執行子執行緒t1中的foo方法,列印foo函式中的第一條列印語句,然後子執行緒t1進入到睡眠狀態。

然後子執行緒t2執行,列印bar函式中的第一條print語句,然後子執行緒t2進入睡眠狀態,程式切換到主執行緒執行

主執行緒列印完”ending”語句,發現子執行緒t1和t2已經被設定為守護執行緒,所以主執行緒不需要再等待兩個子執行緒執行完成,而是立即結束,列印整個程式的執行時間。

整個程式就跟隨主執行緒一起關閉了。

2.3 子執行緒的一些其他方法

isAlive()           #判斷一個執行緒是否是活動執行緒
getName()           #返回執行緒的名字
setName()           #設定執行緒的名字
    import threading
    import time
    
    def foo(n):
        time.sleep(n)
        print("foo func:", n)
    
    def bar(n):
        time.sleep(n)
        print("bar func:", n)
    
    s1 = time.time()
    t1 = threading.Thread(target=foo, args=(3,))
    t1.setDaemon(True)
    
    print("執行緒還未啟動時,判斷t1是否是活動的執行緒:", t1.isAlive())  # 執行緒還未啟動,所以是False
    t1.start()  # 啟動執行緒
    print("執行緒已啟動時,判斷t1是否是活動的執行緒:", t1.isAlive())  # 執行緒已啟動,所以是True
    print("修改前的執行緒名為:",t1.getName())  # 獲取執行緒名
    t1.setName("t1")        #設定執行緒名
    print("修改後的執行緒名為:",t1.getName())  # 獲取執行緒名
    
    t1.join()
    
    print("執行緒執行完成時,判斷t1是不否是活動的執行緒:", t1.isAlive())  # 執行緒已執行完成,所以是False
    
    # print(threading.activeCount())
    print("ending")
    s2 = time.time()
    
    print("cost time:", s2 - s1)

程式執行結果:

執行緒還未啟動時,判斷t1是否是活動的執行緒: False
執行緒已啟動時,判斷t1是否是活動的執行緒: True
修改前的執行緒名為: Thread-1
修改後的執行緒名為: t1
foo func: 3
執行緒執行完成時,判斷t1是不否是活動的執行緒: False
ending
cost time: 3.001171588897705

3.threading模組提供的一些方法

threading.currentThread()   #返回當前的執行緒變數
threading.enumerate()       #返回一個包含正在執行的執行緒的列表,不包括啟動前和終止後的執行緒
threading.activeCount()     #返回正在執行的執行緒數量,等同於len(threading.enumerate())
    import threading
    import time

    def foo(n):
        time.sleep(n)
        print("foo func:", n)

    def bar(n):
        time.sleep(n)
        print("bar func:", n)

    s1 = time.time()
    t1 = threading.Thread(target=foo, args=(3,))
    t1.setDaemon(True)
    t1.start()

    t2 = threading.Thread(target=bar, args=(5,))
    t2.setDaemon(True)
    t2.start()

    print("程式中正在執行的執行緒數量:",threading.activeCount())
    print("程式中當前的執行緒變數:",threading.currentThread())
    print("當前正在執行的執行緒的列表:",threading.enumerate())
    print("ending")
    s2 = time.time()

    print("cost time:", s2 - s1)

程式執行結果:

程式中正在執行的執行緒數量: 3
程式中當前的執行緒變數: <_MainThread(MainThread, started 7064)>
當前正在執行的執行緒的列表: [<_MainThread(MainThread, started 7064)>, <Thread(Thread-1, started daemon 6384)>, <Thread(Thread-2, started daemon 2640)>]
ending
cost time: 0.002000093460083008


相關文章