我有一个带有一个主线程的python程序,让我们说2个其他线程(或者甚至更多,可能并不重要)。我想让主线程休眠直到其他一个线程完成。轮询很容易(通过调用t.join(1)并为每个线程t等待一秒钟)。
是否可以在没有轮询的情况下进行,仅通过
SOMETHING_LIKE_JOIN(1, [t1, t2])
其中t1和t2是线程。线程对象?呼叫必须执行以下操作:休眠1秒,但只要t1,t2中的一个完成就唤醒。与使用两个文件描述符的POSIX select(2)调用非常类似。
答案 0 :(得分:2)
一种解决方案是使用multiprocessing.dummy.Pool
; multiprocessing.dummy
提供的API几乎与multiprocessing
相同,但由线程支持,因此它可以免费获得一个线程池。
例如,你可以这样做:
from multiprocessing.dummy import Pool as ThreadPool
pool = ThreadPool(2) # Two workers
for res in pool.imap_unordered(some_func, list_of_func_args):
# res is whatever some_func returned
multiprocessing.Pool.imap_unordered
会在结果可用时返回结果,无论哪个任务首先完成。
如果您可以使用Python 3.2或更高版本(或为旧版Python安装concurrent.futures
PyPI模块),您可以通过从{{1}创建一个或多个Future
来概括为不同的任务函数},然后将concurrent.futures.wait
与ThreadPoolExecutor
一起使用,或使用return_when=FIRST_COMPLETED
获得类似效果。
答案 1 :(得分:1)
以下是使用条件对象的示例。
from threading import Thread, Condition, Lock
from time import sleep
from random import random
_lock = Lock()
def run(idx, condition):
sleep(random() * 3)
print('thread_%d is waiting for notifying main thread.' % idx)
_lock.acquire()
with condition:
print('thread_%d notifies main thread.' % idx)
condition.notify()
def is_working(thread_list):
for t in thread_list:
if t.is_alive():
return True
return False
def main():
condition = Condition(Lock())
thread_list = [Thread(target=run, kwargs={'idx': i, 'condition': condition}) for i in range(10)]
with condition:
with _lock:
for t in thread_list:
t.start()
while is_working(thread_list):
_lock.release()
if condition.wait(timeout=1):
print('do something')
sleep(1) # <-- Main thread is doing something.
else:
print('timeout')
for t in thread_list:
t.join()
if __name__ == '__main__':
main()
我不认为你在评论中描述了竞争条件。条件对象包含一个锁。当主线程工作时(示例中为sleep(1)),它保持锁定,没有线程可以通知它,直到它完成其工作并释放锁定。
我只是意识到上一个例子中存在竞争条件。我添加了一个全局_lock,以确保在主线程开始等待之前,条件永远不会通知主线程。我不喜欢它是如何工作的,但我还没有想出更好的解决方案......
答案 2 :(得分:-1)
您可以创建一个Thread类,主线程会保留对它的引用。因此,您可以检查线程是否已完成,并使主线程再次轻松继续。
如果这对您没有帮助,我建议您查看队列库!
import threading
import time, random
#THREAD CLASS#
class Thread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.daemon = True
self.state = False
#START THREAD (THE RUN METHODE)#
self.start()
#THAT IS WHAT THE THREAD ACTUALLY DOES#
def run(self):
#THREAD SLEEPS FOR A RANDOM TIME RANGE#
time.sleep(random.randrange(5, 10))
#AFTERWARDS IS HAS FINISHED (STORE IN VARIABLE)#
self.state = True
#RETURNS THE STATE#
def getState(self):
return self.state
#10 SEPERATE THREADS#
threads = []
for i in range(10):
threads.append(Thread())
#MAIN THREAD#
while True:
#RUN THROUGH ALL THREADS AND CHECK FOR ITS STATE#
for i in range(len(threads)):
if threads[i].getState():
print "WAITING IS OVER: THREAD ", i
#SLEEPS ONE SECOND#
time.sleep(1)