簡體   English   中英

試圖了解python多線程

[英]Trying to understand python multithreading

請考慮以下代碼:

import threading

def printer():
    for i in range(2):
        with lock:
            print ['foo', 'bar', 'baz']

def main():
    global lock
    lock = threading.Lock()
    threads = [threading.Thread(target=printer) for x in xrange(2)]
    for t in threads:
        t.start()
        t.join()

main()

我可以理解這段代碼,這很清楚:我們創建了兩個線程,然后按順序運行它們-僅在第一個線程完成時才運行第二個線程。 好的,現在考慮另一個變體:

import threading

def printer():
    for i in range(2):
        with lock:
            print ['foo', 'bar', 'baz']

def main():
    global lock
    lock = threading.Lock()
    threads = [threading.Thread(target=printer) for x in xrange(2)]
    for t in threads:
        t.start()
    for t in threads:
        t.join()

main()

這里會發生什么? 好的,我們並行運行它們,但是讓主線程在第二個變體中等待子線程的目的是什么? 它如何影響輸出?

在第二種變體中,執行順序的定義要少得多。 每次通過打印機中的循環釋放鎖定。 在這兩種變體中,一個線程中都有兩個線程和兩個循環。 在第一個變體中,由於一次只運行一個線程,因此您知道總排序。 在第二個變體中,每次釋放鎖定時,線程運行可能會更改。 所以你可能會得到

  • 線程1循環1
  • 線程1循環2
  • 線程2循環1
  • 線程2循環2

或者*線程2循環1 *線程1循環1 *線程1循環2 *線程2循環2

唯一的限制是給定線程中的loop1在該線程中的循環2之前運行,並且兩個print語句放在一起,因為這兩個語句均被鎖定。

在這種特殊情況下,我不確定第二個變體中對t.join()的調用是否具有可觀察到的效果。 它保證了主線程將是最后一個結束的線程,但是我不確定在此代碼中您能否以任何方式觀察到這一點。 在更復雜的代碼中,加入線程可能很重要,因此僅在所有線程終止后才執行清除操作。 如果您有守護程序線程,這也可能非常重要,因為當所有非守護程序線程終止時,整個程序將終止。

為了更好地理解python中的多線程,您需要首先了解main線程和children線程之間的關系。

main線程是程序的入口,它是由系統在運行腳本時創建的。 例如,在您的腳本中, main函數在main線程中運行。

當您實例化Thread類時, children線程是由您的main線程創建的。

最重要的是主線程如何控制子線程。 基本上, Thread實例是main線程了解並控制該子線程的所有內容。 在創建子線程時,該子線程不會立即運行,直到該線程實例上的主線程調用start函數為止。 啟動子線程之后,您可以假定main線程和child線程現在正在並行運行。

但是更重要的一件事是main線程如何知道child線程的任務已完成。 雖然main線程一無所知任務如何通過做child的線程,它不知道的運行狀態child線程。 Thread.is_alive可以通過main線程檢查Thread.is_alive的狀態。 在實踐中,始終使用Thread.join函數告訴main線程等待,直到child線程完成。 該函數將阻塞main線程。

好的,讓我們檢查一下您困惑的兩個腳本。 對於第一個腳本:

for t in threads:
    t.start()
    t.join()

循環中的children線程start ,然后一個接一個地join 請注意, start不會阻塞main線程,而join會阻塞main線程,直到該child線程完成。 因此,它們按順序運行。

而對於第二個腳本:

for t in threads:
    t.start()
for t in threads:
    t.join()

所有children線程均在第一個循環中啟動。 由於Thread.start函數不會阻塞main線程,因此所有children線程在第一個循環之后並行運行。 在第二個循環中, main線程將逐個等待每個child線程完成的任務。

現在,我認為您應該注意到這兩個腳本之間的區別:在第一個腳本中, children線程一個接一個地運行,而在第二個腳本中,它們同時運行。

python線程還有其他有用的主題:

(1)如何處理鍵盤中斷異常,例如,當我想通過Ctrl-C終止程序時? 只有main線程會收到異常,您必須處理children線程的終止。

(2)多線程與多處理。 盡管我們說線程是並行的,但在CPU級別並不是真正的並行。 因此,如果您的應用程序占用大量CPU,請嘗試進行多處理,如果您的應用程序占用大量I / O,則多線程可能就足夠了。

順便說一句,請仔細閱讀python線程部分的文檔並嘗試一些代碼可以幫助您理解它。

希望這會有所幫助。 謝謝。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM