[英]How does Thread().join work in the following case?
我在一個線程教程中看到了以下代碼:
from time import sleep, perf_counter
from threading import Thread
start = perf_counter()
def foo():
sleep(5)
threads = []
for i in range(100):
t = Thread(target=foo,)
t.start()
threads.append(t)
for i in threads:
i.join()
end = perf_counter()
print(f'Took {end - start}')
當我運行它時,它會打印Took 5.014557975
。 好的,那部分很好。 它不像非線程版本那樣需要 500 秒。
我不明白.join
是如何工作的。 我注意到沒有調用.join
我得到Took 0.007060926999999995
這表明主線程在子線程之前結束。 由於'.join()'應該阻塞,當循環的第一次迭代發生時它不會被阻塞並且必須等待5秒直到第二次迭代? 它如何仍然設法運行?
我一直在閱讀 python 線程並不是真正的多線程,而且它似乎只是(在單核上運行),但如果是這種情況,那么如果它不是並行的,那么后台時間究竟是如何運行的呢?
所以'.join()'應該阻塞,所以當循環的第一次迭代發生時它不會被阻塞並且它必須等待5秒直到第二次迭代?
請記住,所有線程都是同時啟動的,所有線程都需要大約 5 秒。
第二個for
循環等待所有線程完成。 第一個線程大約需要 5 秒才能完成,但其余 99 個線程將大致同時完成,循環的其余 99 次迭代也是如此。 當您在第二個線程上調用join()
時,它要么已經完成,要么將在幾毫秒內完成。
我一直在閱讀 python 線程並不是真正的多線程,而且它似乎只是(在單核上運行),但如果是這種情況,那么如果它不是並行的,那么后台時間究竟是如何運行的呢?
這是一個已經討論過很多的話題,所以我不會添加另一個頁面長的答案。
Tl;博士:是的,Python 多線程對 CPU 密集型任務沒有幫助,但對於花費大量時間等待其他事情(網絡、磁盤 I/O、用戶輸入、時間-基於事件)。
sleep()
屬於后一組任務,因此多線程會加快它的速度,即使它不會同時使用多個內核。
操作系統在線程啟動時處於控制之中,並且操作系統將在線程之間進行上下文切換(我相信這是正確的術語)。
time
功能通過操作系統訪問您計算機上的時鍾- 該時鍾始終在運行。 只要操作系統定期給每個線程時間來訪問一個時鍾,線程的目標就可以判斷它是否已經睡了足夠長的時間。
線程不是並行運行的,操作系統會定期給每個線程一個查看時鍾的機會。
這是正在發生的事情的更詳細的信息。 我將 Thread 子類化並覆蓋了它的run
和join
方法,以便在調用它們時進行記錄。
警告文檔特別指出
只覆蓋
__init__
並run
方法
我很驚訝覆蓋join
沒有引起問題。
from time import sleep, perf_counter
from threading import Thread
import pandas as pd
c = {}
def foo(i):
c[i]['foo start'] = perf_counter() - start
sleep(5)
# print(f'{i} - start:{start} end:{perf_counter()}')
c[i]['foo end'] = perf_counter() - start
class Test(Thread):
def __init__(self,*args,**kwargs):
self.i = kwargs['args'][0]
super().__init__(*args,**kwargs)
def run(self):
# print(f'{self.i} - started:{perf_counter()}')
c[self.i]['thread start'] = perf_counter() - start
super().run()
def join(self):
# print(f'{self.i} - joined:{perf_counter()}')
c[self.i]['thread joined'] = perf_counter() - start
super().join()
threads = []
start = perf_counter()
for i in range(10):
c[i] = {}
t = Test(target=foo,args=(i,))
t.start()
threads.append(t)
for i in threads:
i.join()
df = pd.DataFrame(c)
print(df)
0 1 2 3 4 5 6 7 8 9
thread start 0.000729 0.000928 0.001085 0.001245 0.001400 0.001568 0.001730 0.001885 0.002056 0.002215
foo start 0.000732 0.000931 0.001088 0.001248 0.001402 0.001570 0.001732 0.001891 0.002058 0.002217
thread joined 0.002228 5.008274 5.008300 5.008305 5.008323 5.008327 5.008330 5.008333 5.008336 5.008339
foo end 5.008124 5.007982 5.007615 5.007829 5.007672 5.007899 5.007724 5.007758 5.008051 5.007549
希望您可以看到所有線程都非常接近地按順序啟動; 一旦線程 0加入,在它停止( foo
結束)之前不會發生其他任何事情,然后其他每個線程都加入並終止。
有時一個線程甚至在它加入之前就終止了 - 對於線程一加foo ends
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.