为什么来自ThreadPool的线程不会异步运行?

时间:2014-01-22 09:05:53

标签: python multithreading python-2.7 asynchronous threadpool

我写了以下概念证明代码:

import time
from multiprocessing.pool import ThreadPool

class Maybe:
    def __init__(self):
        self._value = None
        self._exists = False
    def exists(self):
        return self._exists
    def value(self):
        if not self.exists():
            raise ValueError("Maybe doesn't hold any value")
        return self._value
    def set(self, value):
        self._value = value
        self._exists = True
    def unset(self):
        self._value = None
        self._exists = False

class Future(object):

    def __init__(self):
        self._holder = Maybe()
        self._handler = None

    def _set(self, value):
        self._holder.set(value)
        self._invoke()

    def _invoke(self):
        if self._handler and self._holder.exists():
            self._handler(self._holder.value())

    def then(self, handler):
        self._handler = handler
        self._invoke()


def fib(count):
    f,s = 0,1
    for i in xrange(count):
        f,s =s,f+s
    return s

pool = ThreadPool(5)

def test(fun, arg):
    def print_fib(x):
        print("fib => {0}, {1}\n".format(arg, len(str(x))))
    tb = time.time()
    future = Future()
    future.then(print_fib)
    future._async_result = pool.apply_async(fun, [arg], callback=future._set)
    ta = time.time()
    print ("Time elapsed : {0}".format(ta - tb))
    return future


x1=test(fib, 2029)
x2=test(fib, 989999)
x3=test(fib, 103)
x4=test(fib, 38484)
x5=test(fib, 20)

time.sleep(3)

我期待所有调用以异步方式运行。但它们似乎不是异步运行的。例如,带有103参数的调用预计在以989999为参数的调用之前完成。我没有看到这种情况发生。如果我使用更大的参数进行第二次调用,即使第一次调用也需要更多时间。

有人可以解释发生了什么吗?为什么它们不能异步运行?

2 个答案:

答案 0 :(得分:1)

线程是连续运行的。但是fib跑得太快了;因此很难判断它们是否同时运行。 (fib(989999)除外)

请尝试以下操作(我将已用时间打印部件移至print_fib以正确打印已用时间。):

def test(fun, arg):
    def print_fib(x):
        print("fib => {0}, {1}\n".format(arg, len(str(x))))
        ta = time.time()
        print ("Time elapsed : {0}".format(ta - tb))
    tb = time.time()
    future = Future()
    future.then(print_fib)
    future._async_result = pool.apply_async(fun, [arg], callback=future._set)
    return future

x1 = test(time.sleep, 2)
x2 = test(time.sleep, 5)
x3 = test(time.sleep, 1)
x4 = test(time.sleep, 4)
x5 = test(time.sleep, 3)

#time.sleep(10)

x1._async_result.get()
x2._async_result.get()
x3._async_result.get()
x4._async_result.get()
x5._async_result.get()

输出:

fib => 1, 4

Time elapsed : 1.00200009346
fib => 2, 4

Time elapsed : 2.00099992752
fib => 3, 4

Time elapsed : 3.00200009346
fib => 4, 4

Time elapsed : 4.00200009346
fib => 5, 4

Time elapsed : 5.00200009346

答案 1 :(得分:1)

问题是ThreadPool将所有线程设置为守护进程,即如果主线程退出所有线程将终止。 time.sleep(3)不足以让您的流程完成其任务,这就是原因。请注意,您的“已用时间”日志不正确,因为它会测量触发线程所需的时间,而不是实际任务。

您应始终.join个帖子。使用ThreadPool,您可以使用以下代码执行此操作:

...

x1=test(fib, 2029)
x2=test(fib, 989999)
x3=test(fib, 103)
x4=test(fib, 38484)
x5=test(fib, 20)

pool.close()
pool.join()

同时将所有日志移至print_fib函数,它应该按预期工作。