Python多執行緒程式設計(二)

weixin_34248705發表於2017-02-11

我在Python多執行緒程式設計(一) 這篇文章中記錄了一下threading模組的常用方法和兩種寫run()函式的方法。這篇文章寫一下自己遇到過的幾個問題,通過例項重新理解下join()函式,以及多執行緒修改全域性變數時的坑。

首先明確下下join()函式的作用:主執行緒A中建立了一個子執行緒B,並且在主執行緒中呼叫B.join()方法。那麼主執行緒就會在呼叫B.join()這個地方等待,直到子執行緒B完成操作或者子執行緒B超時,主執行緒A才可以繼續往下面執行其他語句

1. 每個執行緒操作一個全域性變數進行累加,最後結果應該是什麼?

下面程式碼中用了10個執行緒去執行一個10000 次的for迴圈,以此累加**COUNT **這個全域性變數,我們COUNT值累加後會是10000嗎?或者是其他的值?

指令碼 1.py

[yantao@yantao thread]$ cat 1.py 
#/usr/bin/python
#coding: utf-8

import threading

COUNT = 0

class AddUp(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        global COUNT
        for i in xrange(10000):
            COUNT += 1
        print 'Current result: ',COUNT

if __name__ == '__main__':
    for i in range(10):
        thread = AddUp()
        thread.start()
        thread.join()
    print 'COUNT: ',COUNT

執行結果如下:

[yantao@yantao thread]$ python 1.py 
Current result:  10000
Current result:  20000
Current result:  30000
Current result:  40000
Current result:  50000
Current result:  60000
Current result:  70000
Current result:  80000
Current result:  90000
Current result:  100000
COUNT:  100000

最後的結果是100000,和“預期”結果相符合。但是,事實並不是這樣的,我們的目的是10個執行緒併發累加得到COUNT的值1.py 指令碼雖然在主執行緒中又產生了10個執行緒,但實際上這10個執行緒是序列的,並不是並行的!
  為什麼呢?來分析下產生執行緒的程式碼:

if __name__ == '__main__':
    for i in range(10):
        thread = AddUp()
        thread.start()
        thread.join()
    print 'COUNT: ',COUNT

我們觀察到子執行緒thread在start()後,我們在主執行緒中立刻呼叫了thread執行緒的join()函式,以此來阻塞當前執行緒(主執行緒)。那麼我們的主執行緒就會停留在join()函式這裡,直到子執行緒返回結果後,主執行緒才會繼續執行for迴圈產生新的執行緒,但是我們繼續呼叫了新執行緒的join()方法,主執行緒會繼續等待直到新的子執行緒返回結果才會繼續執行。如此反覆10次。從這個邏輯可以看出,這裡並沒有併發,只不過是用了10個執行緒分別迴圈10000次,做了主執行緒迴圈100000次就可以做到的事情。 那麼如何做到併發了?只要對1.py稍作更改即可,如下2.py

指令碼 2.py

#/usr/bin/python
#coding: utf-8

import threading

COUNT = 0

class AddUp(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        global COUNT         
        for i in xrange(10000):
            COUNT += 1

if __name__ == '__main__':
    threads = []
    for i in range(10):
        thread = AddUp()
        #print thread.getName()
        threads.append(thread)      #將所有子執行緒放在一個列表裡面
        thread.start()                       #執行緒執行後不阻塞主執行緒,繼續執行for迴圈產生新的執行緒
    for thread in threads:              #在此處阻塞主執行緒,直到所有子執行緒返回
        thread.join()
    print COUNT

多次執行程式看下結果:

[yantao@yantao thread]$ python 2.py 
53359
[yantao@yantao thread]$ python 2.py 
47909
[yantao@yantao thread]$ python 2.py 
52725

從結果看每次執行的並不一樣,這說明這裡確實是併發了,但是為什麼值會不一樣了?因為多個執行緒操作一個全域性變數時,會發生資源搶佔,變數不能按照預定的邏輯進行操作,比如我們這裡得到得結果就不是100000.
  在使用多執行緒時,儘量避免操作全域性變數,以免引發不必要得麻煩,如果非要用,應該做好鎖機制。

相關文章