使用 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有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份