Python: потоки, использующие join () в цикле while - PullRequest
3 голосов
/ 29 октября 2011

Я бы хотел, чтобы цикл while блокировал не более 5 секунд для всех потоков, которые он создает в цикле for. Однако следующий код будет блокироваться потоками один за другим. Как я могу приблизиться к своей цели? Спасибо.

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

Ответы [ 3 ]

3 голосов
/ 29 октября 2011

Вам необходимо использовать условную переменную (threading.Condition в Python). Это позволяет ждать, пока предикат не станет истинным. В вашем случае предикат all threads have finished work or time out exceeded. Вот код, который создает десять потоков и ожидает, пока они не закончатся с истечением 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)

Дополнительная информация на FAQ по comp.programming.threads .

1 голос
/ 29 октября 2011

Одна вещь, которую нужно сделать, это запустить все потоки, а затем перебрать массив и присоединиться.Но я полагаю, это все равно будет ждать до 5 * секунд.В качестве альтернативы вы можете создать один дополнительный поток, который просто ждет ваших потоков бесконечно.Тогда в вашей основной теме вы можете просто подождать дополнительную тему в течение 5 секунд.

0 голосов
/ 29 октября 2011

Пытаетесь ли вы порождать поток каждые 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
...