[英]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()
這里會發生什么? 好的,我們並行運行它們,但是讓主線程在第二個變體中等待子線程的目的是什么? 它如何影響輸出?
在第二種變體中,執行順序的定義要少得多。 每次通過打印機中的循環釋放鎖定。 在這兩種變體中,一個線程中都有兩個線程和兩個循環。 在第一個變體中,由於一次只運行一個線程,因此您知道總排序。 在第二個變體中,每次釋放鎖定時,線程運行可能會更改。 所以你可能會得到
或者*線程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.