簡體   English   中英

Thread().join 在以下情況下如何工作?

[英]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 子類化並覆蓋了它的runjoin方法,以便在調用它們時進行記錄

警告文檔特別指出

覆蓋__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.

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