使用 threading.Thread.join()
Posted
技术标签:
【中文标题】使用 threading.Thread.join()【英文标题】:Use of threading.Thread.join() 【发布时间】:2013-10-08 21:55:25 【问题描述】:我不熟悉 python 中的多线程,并尝试使用线程模块学习多线程。我制作了一个非常简单的多线程程序,但我无法理解threading.Thread.join
方法。
这是我制作的程序的源代码
import threading
val = 0
def increment():
global val
print "Inside increment"
for x in range(100):
val += 1
print "val is now ".format(val)
thread1 = threading.Thread(target=increment, args=())
thread2 = threading.Thread(target=increment, args=())
thread1.start()
#thread1.join()
thread2.start()
#thread2.join()
如果我使用它有什么不同
thread1.join()
thread2.join()
我在上面的代码中注释了什么?我运行了两个源代码(一个带有 cmets 和一个不带 cmets),但输出是相同的。
【问题讨论】:
可能重复:***.com/questions/15085348/… 您希望您的代码工作是因为它是正确的还是偶然的? @Vivek 虽然问的问题的标题几乎相同,但我的问题有点简单,只要求 join() 函数的基本工作。由于我是线程新手,我无法理解您指出的链接给出的答案。因此,我认为最好问一个新的简单问题。 那里的答案对我来说甚至有点难以理解。 【参考方案1】:对thread1.join()
的调用会阻塞您进行调用的线程,直到thread1
完成。就像wait_until_finished(thread1)
。
例如:
import time
def printer():
for _ in range(3):
time.sleep(1.0)
print "hello"
thread = Thread(target=printer)
thread.start()
thread.join()
print "goodbye"
打印
hello
hello
hello
goodbye
——如果没有 .join()
调用,goodbye
将首先出现,然后是 3 * hello
。
另外,请注意 Python 中的线程不会提供任何额外的性能(就 CPU 处理能力而言),因为有一个叫做 Global Interpreter Lock 的东西,所以虽然它们对于产生潜在的阻塞(例如 IO、网络)很有用和耗时的任务(例如数字运算)以保持主线程空闲用于其他任务,它们不允许您利用多个内核或 CPU;为此,请查看 multiprocessing
,它使用子进程但公开了与 threading
等效的 API。
PLUG: ...也是由于上述原因,如果您对并发感兴趣,您可能还想研究一个名为 Gevent 的优秀库,它本质上只是让线程更容易使用,更快(当您有许多并发活动时)并且不太容易出现与并发相关的错误,同时允许您以与“真实”线程相同的方式进行编码。此外,Twisted、Eventlet、Tornado 和许多其他的都是等效的或可比的。此外,无论如何,我强烈建议阅读这些经典:
Generator Tricks for Systems Programmers A Curious Course on Coroutines and Concurrency【讨论】:
“另外,请注意 Python 中的线程不会提供任何额外的性能,因为有一个叫做全局解释器锁的东西......”这是一个过于宽泛的概括,因此是错误的。线程非常适合 I/O 绑定任务,并且肯定会在那里提供性能优势。有很多线程在讨论这一点。 @erewok:你一定错过了我说 “虽然它们有助于产生潜在的阻塞和耗时” 和 “它们不允许您可以利用多个内核或 CPU”...无论如何,我已经更新了我的答案,以便更清楚地说明这一点。 我认为编辑有助于澄清线程可能有用的地方。感谢您提供它。 我仍然不明白为什么 Python 没有选择更好的名称而不是“加入”? 'wait_until_finished' 或类似的行不是更直观吗?【参考方案2】:我修改了代码,以便您了解 join 的工作原理。 因此,使用 cmets 和不使用 cmets 运行此代码并观察两者的输出。
val = 0
def increment(msg,sleep_time):
global val
print "Inside increment"
for x in range(10):
val += 1
print "%s : %d\n" % (msg,val)
time.sleep(sleep_time)
thread1 = threading.Thread(target=increment, args=("thread_01",0.5))
thread2 = threading.Thread(target=increment, args=("thread_02",1))
thread1.start()
#thread1.join()
thread2.start()
#thread2.join()
【讨论】:
感谢您的回答,您的代码清楚地显示了使用 join() 和不使用它之间的区别【参考方案3】:正如the relevant documentation 所说,join
让调用者等待线程终止。
在您的情况下,输出是相同的,因为 join
不会改变程序行为 - 它可能被用来干净地退出程序,只有当所有线程都终止时。
【讨论】:
以上是关于使用 threading.Thread.join()的主要内容,如果未能解决你的问题,请参考以下文章
在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?
Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)