我在学习python线程时遇到了join()。

作者告诉,如果线程在守护进程模式,那么我需要使用join(),以便线程可以在主线程终止之前完成自己。

但我也见过他使用t.join(),即使t不是daemon

示例代码如下所示

import threading
import time
import logging

logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-10s) %(message)s',
                    )

def daemon():
    logging.debug('Starting')
    time.sleep(2)
    logging.debug('Exiting')

d = threading.Thread(name='daemon', target=daemon)
d.setDaemon(True)

def non_daemon():
    logging.debug('Starting')
    logging.debug('Exiting')

t = threading.Thread(name='non-daemon', target=non_daemon)

d.start()
t.start()

d.join()
t.join()

我不知道t.join()的用途是什么,因为它不是守护进程,即使我删除它,我也看不到任何变化


当前回答

谢谢你的这篇文章——它也帮了我很多。

我今天学了一些关于.join()的知识。

这些线程并行运行:

d.start()
t.start()
d.join()
t.join()

这些顺序运行(不是我想要的):

d.start()
d.join()
t.start()
t.join()

特别是,我试图聪明和整洁:

class Kiki(threading.Thread):
    def __init__(self, time):
        super(Kiki, self).__init__()
        self.time = time
        self.start()
        self.join()

这个工作!但它是按顺序运行的。我可以把self.start()放在__ init __中,但不是self.join()。这必须在启动每个线程之后完成。

Join()是导致主线程等待线程完成的原因。否则,线程将自行运行。

因此,有一种方法可以将join()视为主线程上的“hold”——它在某种程度上解除线程的线程,并在主线程继续执行之前在主线程中顺序执行。它确保主线程向前移动之前线程已经完成。请注意,这意味着如果在调用join()之前线程已经完成,也没关系——当调用join()时,主线程会立即被释放。

事实上,我刚刚想到主线程会在d.t join()上等待,直到线程d结束,然后才移动到t.t join()。

事实上,为了更清楚地说明问题,请考虑以下代码:

import threading
import time

class Kiki(threading.Thread):
    def __init__(self, time):
        super(Kiki, self).__init__()
        self.time = time
        self.start()

    def run(self):
        print self.time, " seconds start!"
        for i in range(0,self.time):
            time.sleep(1)
            print "1 sec of ", self.time
        print self.time, " seconds finished!"


t1 = Kiki(3)
t2 = Kiki(2)
t3 = Kiki(1)
t1.join()
print "t1.join() finished"
t2.join()
print "t2.join() finished"
t3.join()
print "t3.join() finished"

它产生这样的输出(注意print语句是如何相互衔接的)。

$ python test_thread.py
32   seconds start! seconds start!1

 seconds start!
1 sec of  1
 1 sec of 1  seconds finished!
 21 sec of
3
1 sec of  3
1 sec of  2
2  seconds finished!
1 sec of  3
3  seconds finished!
t1.join() finished
t2.join() finished
t3.join() finished
$ 

t1.join()占用主线程。在t1.join()结束之前,所有三个线程都完成了,主线程继续执行打印,然后t2.join(),然后打印,然后t3.join(),然后打印。

修正的欢迎。我也是线程的新手。

(注意:如果你感兴趣的话,我正在为DrinkBot编写代码,我需要线程来并发地运行配料泵,而不是按顺序运行——这样就可以减少等待每种饮料的时间。)

其他回答

下面的例子演示了.join()操作:

import threading
import time

def threaded_worker():
    for r in range(10):
        print('Other: ', r)
        time.sleep(2)

thread_ = threading.Timer(1, threaded_worker)
thread_.daemon = True  # If the main thread is killed, this thread will be killed as well. 
thread_.start()

flag = True

for i in range(10):
    print('Main: ', i)
    time.sleep(2)
    if flag and i > 4:
        print(
            '''
            Threaded_worker() joined to the main thread. 
            Now we have a sequential behavior instead of concurrency.
            ''')
        thread_.join()
        flag = False

Out:

Main:  0
Other:  0
Main:  1
Other:  1
Main:  2
Other:  2
Main:  3
Other:  3
Main:  4
Other:  4
Main:  5
Other:  5

            Threaded_worker() joined to the main thread. 
            Now we have a sequential behavior instead of concurrency.
            
Other:  6
Other:  7
Other:  8
Other:  9
Main:  6
Main:  7
Main:  8
Main:  9

When making join(t) function for both non-daemon thread and daemon thread, the main thread (or main process) should wait t seconds, then can go further to work on its own process. During the t seconds waiting time, both of the children threads should do what they can do, such as printing out some text. After the t seconds, if non-daemon thread still didn't finish its job, and it still can finish it after the main process finishes its job, but for daemon thread, it just missed its opportunity window. However, it will eventually die after the python program exits. Please correct me if there is something wrong.

直接从医生那里

加入((超时)) 等待线程终止。这将阻塞调用线程,直到调用join()方法的线程终止—正常终止或通过未处理的异常终止—或者直到可选超时发生。

这意味着生成t和d的主线程等待t完成,直到它完成。

根据程序使用的逻辑,您可能希望等到主线程结束后再继续执行。

文档中还提到:

一个线程可以被标记为“守护线程”。这个标志的意义在于,当只剩下守护线程时,整个Python程序将退出。

举个简单的例子:

def non_daemon():
    time.sleep(5)
    print 'Test non-daemon'

t = threading.Thread(name='non-daemon', target=non_daemon)

t.start()

最后是:

print 'Test one'
t.join()
print 'Test two'

这将输出:

Test one
Test non-daemon
Test two

在这里,主线程显式地等待t线程完成,直到它第二次调用print。

另一种情况是:

print 'Test one'
print 'Test two'
t.join()

我们将得到这样的输出:

Test one
Test two
Test non-daemon

在这里,我们在主线程中完成工作,然后等待t线程完成。在这种情况下,我们甚至可以删除显式连接t.join(),程序将隐式地等待t完成。

您可能会说:“使用join()有什么用?”实际上,这和“关闭文件有什么用,因为python和操作系统会在程序退出时为我关闭文件?”的答案是一样的。

这只是一个好的编程问题。您应该在代码中线程不应该再运行的地方join()您的线程,因为您必须确保线程的运行不会干扰您自己的代码,或者您希望在更大的系统中正确地运行。

您可能会说“我不希望我的代码延迟给出答案”,只是因为join()可能需要额外的时间。在某些情况下,这可能是完全有效的,但现在你需要考虑到你的代码“留下了粗糙的东西,让python和操作系统来清理”。如果您这样做是出于性能原因,我强烈建议您记录该行为。如果您正在构建其他人希望使用的库/包,则尤其如此。

除了性能原因之外,没有理由不使用join(),而且我认为您的代码不需要执行得那么好。

使用join -解释器将等待您的进程完成或终止

>>> from threading import Thread
>>> import time
>>> def sam():
...   print 'started'
...   time.sleep(10)
...   print 'waiting for 10sec'
... 
>>> t = Thread(target=sam)
>>> t.start()
started

>>> t.join() # with join interpreter will wait until your process get completed or terminated
done?   # this line printed after thread execution stopped i.e after 10sec
waiting for 10sec
>>> done?

没有join -解释器不会等待进程被终止,

>>> t = Thread(target=sam)
>>> t.start()
started
>>> print 'yes done' #without join interpreter wont wait until process get terminated
yes done
>>> waiting for 10sec