Python多線程中阻塞(join)與鎖(Lock)的使用誤區__Python

來源:互聯網
上載者:User
關於阻塞主線程 join的錯誤用法

Thread.join() 作用為阻塞主線程,即在子線程未返回的時候,主線程等待其返回然後再繼續執行.

join不能與start在迴圈裡連用
以下為錯誤碼,代碼建立了5個線程,然後用一個迴圈啟用線程,啟用之後令其阻塞主線程.

threads = [Thread() for i in range(5)]for thread in threads:    thread.start()    thread.join()

執行過程:
1. 第一次迴圈中,主線程通過start函數啟用線程1,線程1進行計算.
2. 由於start函數不阻塞主線程,線上程1進行運算的同時,主線程向下執行join函數.
3. 執行join之後,主線程被線程1阻塞,線上程1返回結果之前,主線程無法執行下一輪迴圈.
4. 線程1計算完成之後,解除對主線程的阻塞.
5. 主線程進入下一輪迴圈,啟用線程2並被其阻塞…

如此往複,可以看出,本來應該並發的五個線程,在這裡變成了順序隊列,效率和單線程無異. join的正確用法

使用兩個迴圈分別處理start和join函數.即可實現並發.

threads = [Thread() for i in range(5)]for thread in threads:    thread.start()for thread in threads:    thread.join()
time.sleep代替join進行調試

之前在一些項目裡看到過這樣的代碼,使用time.sleep代替join手動阻塞主線程.
在所有子線程返回之前,主線程陷入無線迴圈而不能退出.

for thread in threads:    thread.start()while 1:    if thread_num == 0:        break    time.sleep(0.01)
關於線程鎖(threading.Lock) 單核CPU+PIL是否還需要鎖?

非原子操作 count = count + 1 理論上是線程不安全的.
使用3個線程同時執行上述操作改變全域變數count的值,並查看程式執行結果.
如果結果正確,則表示未出現線程衝突.

使用以下代碼測試

# -*- coding: utf-8 -*-import threadingimport timecount = 0class Counter(threading.Thread):    def __init__(self, name):        self.thread_name = name        super(Counter, self).__init__(name=name)    def run(self):        global count        for i in xrange(100000):            count = count + 1counters = [Counter('thread:%s' % i) for i in range(5)]for counter in counters:    counter.start()time.sleep(5)print 'count=%s' % count

運行結果:count=275552

事實上每次運行結果都不相同且不正確,這證明單核CPU+PIL仍無法保證安全執行緒,需要加鎖.

加鎖後的正確代碼:

# -*- coding: utf-8 -*-import threadingimport timecount = 0lock = threading.Lock()class Counter(threading.Thread):    def __init__(self, name):        self.thread_name = name        self.lock = threading.Lock()        super(Counter, self).__init__(name=name)    def run(self):        global count        global lock        for i in xrange(100000):            lock.acquire()            count = count + 1            lock.release()counters = [Counter('thread:%s' % i) for i in range(5)]for counter in counters:    counter.start()time.sleep(5)print 'count=%s' % count

結果: count=500000 注意鎖的全域性

這是一個簡單的Python文法問題,但在邏輯複雜時有可能被忽略.
要保證鎖對於多個子線程來說是共用的,即不要在Thread的子類內部建立鎖.

以下為錯誤碼

# -*- coding: utf-8 -*-import threadingimport timecount = 0# lock = threading.Lock() # 正確的聲明位置class Counter(threading.Thread):    def __init__(self, name):        self.thread_name = name        self.lock = threading.Lock() # 錯誤的聲明位置        super(Counter, self).__init__(name=name)    def run(self):        global count        for i in xrange(100000):            self.lock.acquire()            count = count + 1            self.lock.release()counters = [Counter('thread:%s' % i) for i in range(5)]for counter in counters:    print counter.thread_name    counter.start()time.sleep(5)print 'count=%s' % count
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.