等待线程完成使用join。很基本的

时间:2012-02-25 20:31:49

标签: python multithreading join

我有一个非常基本的任务,但我有一个问题让我的主线程等待我生成的所有其他线程完成。

这段代码没有做太多任何事情,它只是作为一个线程练习。

这是我的代码:

import time
from threading import Thread

def printNumbers(lowEnd, highEnd):
    while(lowEnd <= highEnd):
        print(repr(lowEnd))
        lowEnd += 1


countTo = 100000

#Test using 1 thread.        
startSingleThread = time.clock()
printNumbers(0,countTo)
elapsedSingleThread = (time.clock() - startSingleThread)

#Test using 10 threads
numberOfThreads      = 10
countAmountPerThread = countTo/numberOfThreads

startTenThread = time.clock()
for i in range(numberOfThreads):
    threadLowEnd  = i*countAmountPerThread
    threadHighEnd = (i+1)*countAmountPerThread
    t = Thread(target=printNumbers, args=(threadLowEnd,threadHighEnd,))
    t.start()

#Join all existing threads to main thread.
for thread in threading.enumerate():
    if thread is not threading.currentThread():
        thread.join()

elapsedTenThread = (time.clock() - startTenThread)

print("Time for 1 thread: " + repr(elapsedSingleThread))
print("time for 10 threads: " + repr(elapsedTenThread))

2 个答案:

答案 0 :(得分:6)

你看不到stderr,因为你打印了很多东西,但是你有这个错误:

Traceback (most recent call last):
  File "test.py", line 29, in <module>
    for thread in threading.enumerate():
NameError: name 'threading' is not defined

如果我将import threading添加到顶部,我会收到此输出:

Time for 1 thread: 1.0224820000000001
time for 10 threads: 1.421281

...这可能是你期望看到的,因为它是在打印完所有数字后发生的。

答案 1 :(得分:3)

我已经和它斗争了一段时间,我发现了一种适合我的方式 - 它是我在网上找到的东西的集合,现在它是我使用多线程应用程序时的主要“模式”。它没有具体回答您的问题,但它显示了以Pythonic方式利用标准库的方法。但是,请记住,没有打扰阅读标准的图书馆文档。

from threading import Thread, Lock
from Queue import Queue
from datetime import datetime
import time
import random

class Worker(Thread):
    """This is the main worker - it will process jobs as long as the "job
    queue" has jobs available.

    """
    # this lock is used to avoid messing up the screen output - only
    # one worker will write to screen at a given time. It is
    # technically a Mutual Exclusion (mutex)
    screen_mutex = Lock()

    def __init__(self, queue):
        # initialize the base class
        super(Worker, self).__init__()
        self.queue = queue

    def log(self, message):
        """This convenience function is used to print a message to the
        screen. You are better off using the logging module, but
        beware! It is not thread safe (use a server).

        """
        Worker.screen_mutex.acquire()        
        print("{timestamp:%d-%b-%Y %H:%M:%S.%f UTC} "
              "{name}: {message}".format(timestamp=datetime.utcnow(),
                                         name=self.getName(),
                                         message=message))
        Worker.screen_mutex.release()

    def run(self):
        """This is the method called when you start the thread."""
        # The following is an infinite loop which will continue
        # processing jobs as long as there are jobs available in the
        # queue
        while True:
            # this is how you get a job from the queue - this call
            # will block until a job is available, or when the parent
            # thread finishes
            job = self.queue.get()

            # in this case the job is simply a random number
            # indicating how many seconds to sleep (typical example)
            self.log("sleeping for {0} seconds".format(job))            
            time.sleep(job)            
            self.log("finished sleeping")
            # when the job is done, you signal the queue - refer to
            # the Queue module documentation
            self.queue.task_done()


def main(number_of_jobs=10, number_of_workers=3):
    # create the queue where you will put the jobs
    queue = Queue()

    # create the pool of workers (notice that you pass them the queue
    # upon construction). 
    for _ in range(number_of_workers):
        worker = Worker(queue)
        # you "daemonize" a thread to ensure that the threads will
        # close when the main program finishes
        worker.daemon = True        
        worker.start()

    # now it is time to add the jobs to the queue
    for _ in range(number_of_jobs):
        # a random duration between 2 and 5 seconds
        duration = random.randint(2,5) 
        queue.put(duration)

    # now wait for all workers to finish - JOIN THE QUEUE
    queue.join()


if __name__ == "__main__":
    import sys
    if len(sys.argv) == 3:
        nj = int(sys.argv[1])
        nw = int(sys.argv[2])
    else:
        nj = 10
        nw = 3

    # call main             
    main(nj, nw)

示例输出:

computer$ python example.py
25-Feb-2012 21:21:25.924856 UTC Thread-1: sleeping for 2 seconds
25-Feb-2012 21:21:25.925439 UTC Thread-2: sleeping for 3 seconds
25-Feb-2012 21:21:25.925523 UTC Thread-3: sleeping for 5 seconds
25-Feb-2012 21:21:27.925513 UTC Thread-1: finished sleeping
25-Feb-2012 21:21:27.925696 UTC Thread-1: sleeping for 5 seconds
25-Feb-2012 21:21:28.925561 UTC Thread-2: finished sleeping
25-Feb-2012 21:21:28.925742 UTC Thread-2: sleeping for 5 seconds
25-Feb-2012 21:21:30.925547 UTC Thread-3: finished sleeping
25-Feb-2012 21:21:30.925728 UTC Thread-3: sleeping for 5 seconds
25-Feb-2012 21:21:32.925781 UTC Thread-1: finished sleeping
25-Feb-2012 21:21:32.925963 UTC Thread-1: sleeping for 5 seconds
25-Feb-2012 21:21:33.925822 UTC Thread-2: finished sleeping
25-Feb-2012 21:21:33.926003 UTC Thread-2: sleeping for 2 seconds
25-Feb-2012 21:21:35.925833 UTC Thread-3: finished sleeping
25-Feb-2012 21:21:35.926013 UTC Thread-3: sleeping for 3 seconds
25-Feb-2012 21:21:35.926244 UTC Thread-2: finished sleeping
25-Feb-2012 21:21:35.926420 UTC Thread-2: sleeping for 5 seconds
25-Feb-2012 21:21:37.926035 UTC Thread-1: finished sleeping
25-Feb-2012 21:21:38.926158 UTC Thread-3: finished sleeping
25-Feb-2012 21:21:40.926697 UTC Thread-2: finished sleeping
computer$