我有这个python线程代码。
import threading
def sum(value):
sum = 0
for i in range(value+1):
sum += i
print "I'm done with %d - %d\n" % (value, sum)
return sum
r = range(500001, 500000*2, 100)
ts = []
for u in r:
t = threading.Thread(target=sum, args = (u,))
ts.append(t)
t.start()
for t in ts:
t.join()
执行此操作,我有数百个线程在工作。
但是,当我在t.start()之后移动t.join()时,我只有两个线程在工作。
for u in r:
t = threading.Thread(target=sum, args = (u,))
ts.append(t)
t.start()
t.join()
我使用不调用t.join()的代码进行了测试,但似乎工作正常吗?
那么何时,如何以及如何使用thread.join()?
答案 0 :(得分:4)
您似乎不明白Thread.join
的作用。调用join
时,当前线程将阻止,直到该线程结束。所以你正在等待线程完成,阻止你启动任何其他线程。
join
背后的想法是在继续之前等待其他线程。在您的情况下,您希望等待所有线程在主程序结束时完成。否则,如果你没有这样做,并且主程序将结束,那么它创建的所有线程都将被终止。所以通常,你应该在最后有一个循环,它连接所有创建的线程,以防止主线程提前退出。
答案 1 :(得分:3)
简短回答:这一个:
for t in ts:
t.join()
通常是启动小线程数的惯用方法。执行.join
意味着主线程在执行之前等待给定线程完成。您通常在启动所有线程后执行此操作。
更长的答案:
len(list(range(500001, 500000*2, 100)))
Out[1]: 5000
您尝试一次启动5000个主题。你的电脑仍然是一块奇迹!
您在调度工作程序的循环中.join
的方法永远不会有超过2个线程(即只有一个工作线程)同时进行。您的主线程必须等待每个工作线程完成才能继续下一个。您已经防止了计算机崩溃,但是您的代码将比您从未首先使用过线程更慢!
此时我还在谈论GIL,但我暂时把它放在一边。将线程创建限制为合理限制(即多于一个,小于5000)所需的是ThreadPool
。有多种方法可以做到这一点。你可以自己动手 - 这对于threading.Semaphore
来说相当简单。您可以使用3.2 +' concurrent.futures
包。你可以使用一些第三方解决方案。由您决定,每个API都会有不同的API,因此我无法进一步讨论。
强制性GIL讨论
cPython程序员必须与GIL一起生活。简而言之,Global Interpreter Lock意味着只有一个线程可以一次执行python字节码。这意味着在处理器绑定的任务上(比如添加一堆数字),线程不会导致任何加速。实际上,设置和拆除线程所涉及的开销(更不用说上下文切换)将导致速度减慢。线程处理更有利于提高I / O绑定任务的收益,例如检索一堆URL。
multiprocessing
和朋友们通过使用多个进程来回避GIL限制。这不是免费的 - 进程之间的数据传输是昂贵的,因此需要非常谨慎地不要编写依赖于共享状态的工作者。
答案 2 :(得分:1)
join()等待你的线程完成,所以第一次使用会启动一百个线程,然后等待所有线程完成。第二次使用在每个线程启动另一个线程之前等待它的结束,这样做会破坏线程的目的。
第一次使用最有意义。你运行线程(所有这些)进行一些并行计算,然后等到所有这些都完成后再继续使用结果,以确保工作完成(即结果实际存在)。 / p>