Python:在while循环中使用join()的线程

3 投票
3 回答
5819 浏览
提问于 2025-04-17 05:14

我希望我的while循环在for循环中创建的所有线程最多只阻塞5秒钟。但是,下面的代码会让线程一个接一个地阻塞。请问我该怎么做才能实现我的目标呢?谢谢。

threads = []
while True:
    for 3:
        newThread = threading.Thread(..)
        threads.append(newThread)
        newThread.start()
        newThread.join(5)

3 个回答

0

你是不是想每隔5秒钟启动一个新线程,但如果已经在运行的线程结束了,你希望能更早地启动一个新线程?如果是这样的话,你可以使用一个叫做 threading.Event 的东西来通知你某个工作线程结束了,然后用 event.wait(timeout) 来最多等待5秒钟,看看有没有这个通知:

import threading
import time
import logging

logger=logging.getLogger(__name__)

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s: %(message)s',
                    datefmt='%H:%M:%S')

def foo_event(n,e):
    time.sleep(n)
    name=threading.current_thread().name
    logger.info('{n}: setting event'.format(n=name))
    e.set()

def main():
    e=threading.Event()
    threads=[]
    N=5
    for i in range(3):
        t=threading.Thread(target=foo_event,args=(N+1,e,),name='worker-{i}'.format(i=i))
        threads.append(t)
        t.daemon=True
        t.start()
        logger.info('entering wait')
        e.wait(N)
        logger.info('exit wait')
        e.clear()

main()

这样就可以实现了

05:06:34: entering wait
05:06:39: exit wait                 <-- Wait 5 seconds
05:06:39: entering wait
05:06:40: worker-0: setting event   
05:06:40: exit wait                 <-- Wait <5 seconds
05:06:40: entering wait
05:06:45: worker-1: setting event
05:06:45: exit wait                 <-- Wait 5 seconds
2

一种做法是先启动所有的线程,然后遍历数组并把它们合并。不过,我想这样的话,还是会等到总共5乘以线程数量的秒数。另一种方法是可以再创建一个额外的线程,这个线程就一直等着你的其他线程完成。然后在你的主线程中,你只需要等这个额外的线程5秒钟就可以了。

3

你需要使用条件变量(在Python中是threading.Condition)。它的作用是让你等待某个条件变为真。在你的情况下,这个条件是所有线程都完成工作或者超时。下面的代码创建了十个线程,并等待它们在5秒内完成。详细的日志会帮助你理解:

import threading
import time
import logging


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


NUM_OF_THREADS = 10
TIMEOUT = 5


def sleeping_thread(delay, cond):
    logging.debug("Hi, I'm going to delay by %d sec." % delay)
    time.sleep(delay)
    logging.debug("I was sleeping for %d sec." % delay)
    cond.acquire()
    logging.debug("Calling notify().")
    cond.notify()
    cond.release()


def create_sleeping_thread(delay, cond):
    return threading.Thread(target=sleeping_thread,
                            args=(delay, cond))


if __name__ == '__main__':
    cond = threading.Condition(threading.Lock())
    cond.acquire()

    working_counter = NUM_OF_THREADS
    for i in xrange(NUM_OF_THREADS):
        t = create_sleeping_thread(i, cond)
        t.start()

    start_time = time.time()
    while working_counter > 0 and (time.time() - start_time < TIMEOUT):
        cond.wait()
        working_counter -= 1
        logging.debug('%d workers still working', working_counter)
    cond.release()
    logging.debug('Finish waiting for threads (%d workers still working)',
                 working_counter)

更多信息可以查看comp.programming.threads FAQ

撰写回答