Метод Дункана, вероятно, лучший и является тем, что я бы рекомендовал. Меня слегка раздражало отсутствие «дождаться следующего завершенного потока, чтобы закончить», но, поэтому, я просто написал это, чтобы попробовать. Кажется, работает. Просто используйте MWThread
вместо threading.thread
, и вы получите эту новую функцию wait_for_thread
.
Глобальные переменные являются немного klunky; альтернативой было бы сделать их переменными уровня класса. Но если это скрыто в модуле (mwthread.py или что-то еще), это должно быть хорошо в любом случае.
#! /usr/bin/env python
# Example of how to "wait for"/join whichever threads is/are done,
# in (more or less) the order they're done.
import threading
from collections import deque
_monitored_threads = []
_exited_threads = deque()
_lock = threading.Lock()
_cond = threading.Condition(_lock)
class MWThread(threading.Thread):
"""
multi-wait-able thread, or monitored-wait-able thread
"""
def run(self):
tid = threading.current_thread()
try:
with _lock:
_monitored_threads.append(tid)
super(MWThread, self).run()
finally:
with _lock:
_monitored_threads.remove(tid)
_exited_threads.append(tid)
_cond.notifyAll()
def wait_for_thread(timeout=None):
"""
Wait for some thread(s) to have finished, with optional
timeout. Return the first finished thread instance (which
is removed from the finished-threads queue).
If there are no unfinished threads this returns None
without waiting.
"""
with _cond:
if not _exited_threads and _monitored_threads:
_cond.wait(timeout)
if _exited_threads:
result = _exited_threads.popleft()
else:
result = None
return result
def main():
print 'testing this stuff'
def func(i):
import time, random
sleeptime = (random.random() * 2) + 1
print 'thread', i, 'starting - sleep for', sleeptime
time.sleep(sleeptime)
print 'thread', i, 'finished'
threads = [MWThread(target=func, args=(i,)) for i in range(3)]
for th in threads:
th.start()
i = 0
while i < 3:
print 'main: wait up to .5 sec'
th = wait_for_thread(.5)
if th:
print 'main: got', th
th.join()
i += 1
else:
print 'main: timeout'
print 'I think I collected them all'
print 'result of wait_for_thread():'
print wait_for_thread()
if __name__ == '__main__':
main()
Это не ответит на вопрос о основном потоке, ожидающем завершения двух потоков, а затем продолжения: вместо этого вы передали всю оставшуюся активность на второй поток, чтобы завершить, что может быть не так, как требуется. – Duncan
true; handle_two_threads_done() должен, вероятно, установить вместо этого событие. Ред. –
Ummm, списки Python являются потокобезопасными? В самом деле? Я думал, что нужно использовать Queue() для согласованности потоков! –