Python中多線程及程式鎖淺析_python

來源:互聯網
上載者:User

Python中多線程使用到Threading模組。Threading模組中用到的主要的類是Thread,我們先來寫一個簡單的多線程代碼:

複製代碼 代碼如下:

# coding : uft-8
__author__ = 'Phtih0n'
import threading

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

    def run(self):
        global n
        print n
        n += 1

if "__main__" == __name__:
    n = 0
    ThreadList = []
    for i in range(0, 10):
        t = MyThread()
        ThreadList.append(t)
    for t in ThreadList:
        t.start()
    for t in ThreadList:
        t.join

最普通的一個多線程小例子。我一筆帶過地講一講,我建立了一個繼承Thread類的子類MyThread,作為我們的線程啟動類。按照規定,重寫Thread的run方法,我們的線程啟動起來後會自動調用該方法。於是我首先建立了10個線程,並將其加入列表中。再使用一個for迴圈,開啟每個線程。在使用一個for迴圈,調用join方法等待所有線程結束才退出主線程。

這段代碼看似簡單,但實際上隱藏著一個很大的問題,只是在這裡沒有體現出來。你真的以為我建立了10個線程,並按順序調用了這10個線程,每個線程為n增加了1.實際上,有可能是A線程執行了n++,再C線程執行了n++,再B線程執行n++。

這裡涉及到一個“鎖”的問題,如果有多個線程同時操作一個對象,如果沒有很好地保護該對象,會造成程式結果的不可預期(比如我們在每個線程的run方法中加入一個time.sleep(1),並同時輸出線程名稱,則我們會發現,輸出會亂七八糟。因為可能我們的一個print語句只列印出一半的字元,這個線程就被暫停,執行另一個去了,所以我們看到的結果很亂),這種現象叫做“線程不安全”:

於是,Threading模組為我們提供了一個類,Threading.Lock,鎖。我們建立一個該類對象,線上程函數執行前,“搶佔”該鎖,執行完成後,“釋放”該鎖,則我們確保了每次只有一個線程佔有該鎖。這時候對一個公用的對象進行操作,則不會發生線程不安全的現象了。

於是,我們把代碼更改如下:

複製代碼 代碼如下:

# coding : uft-8
__author__ = 'Phtih0n'
import threading, time

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

    def run(self):
        global n, lock
        time.sleep(1)
        if lock.acquire():
            print n , self.name
            n += 1
            lock.release()

if "__main__" == __name__:
    n = 1
    ThreadList = []
    lock = threading.Lock()
    for i in range(1, 200):
        t = MyThread()
        ThreadList.append(t)
    for t in ThreadList:
        t.start()
    for t in ThreadList:
        t.join()

最後執行結果:

我們看到,我們先建立了一個threading.Lock類對象lock,在run方法裡,我們使用lock.acquire()獲得了這個鎖。此時,其他的線程就無法再獲得該鎖了,他們就會阻塞在“if lock.acquire()”這裡,直到鎖被另一個線程釋放:lock.release()。

所以,if語句中的內容就是一塊完整的代碼,不會再存在執行了一半就暫停去執行別的線程的情況。所以最後結果是整齊的。

就如同在java中,我們使用synchronized關鍵字修飾一個方法,目的一樣,讓某段代碼被一個線程執行時,不會打斷跳到另一個線程中。

這是多線程佔用一個公用對象時候的情況。如果多個線程要調用多個現象,而A線程調用A鎖佔用了A對象,B線程調用了B鎖佔用了B對象,A線程不能調用B對象,B線程不能調用A對象,於是一直等待。這就造成了線程“死結”。

Threading模組中,也有一個類,RLock,稱之為可重新進入鎖。該鎖對象內部維護著一個Lock和一個counter對象。counter對象記錄了acquire的次數,使得資源可以被多次require。最後,當所有RLock被release後,其他線程才能擷取資源。在同一個線程中,RLock.acquire可以被多次調用,利用該特性,可以解決部分死結問題。

死結問題很複雜,多年來人們想出了很多演算法來解決它。我就不再多說,具體還是要大家參閱協助文檔。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.