程序适用于map()但使用pool.map()引发TypeError

时间:2014-12-30 11:26:50

标签: python python-2.7 multiprocessing python-multiprocessing

我确实有一个程序,它已经使用了很长一段时间,但它已经被使用和工作了。它使用多处理,因为必须多次对不同的数据执行相同的任务。

我现在触摸了程序添加一个新参数,测试它并注意到它出现了错误。此外,早期(版本控制)版本也会出现相同的错误。完整错误如下所示:

Exception in thread Thread-2:
    Traceback (most recent call last):
        File "/usr/lib64/python2.7/threading.py", line 811, in __bootstrap_inner
            self.run()
        File "/usr/lib64/python2.7/threading.py", line 764, in run
            self.__target(*self.__args, **self.__kwargs)
        File "/usr/lib64/python2.7/multiprocessing/pool.py", line 342, in _handle_tasks
           put(task)
TypeError: 'NoneType' object is not callable

就是这样。说实话,对我来说并不多。在尝试调试时,我想到尝试使用普通map()而不是合并版本pool.map。然后脚本运行正常。

我无法想出一个重现错误的最小例子,但我可以想出一个例子,一切正常,就像预期一样:

import random
import time
from multiprocessing import Pool


def do_work(x, y, z):
     time.sleep(random.random() * 2)
     print x + y + z

def do_one(arguments):
    print "doing one"
    do_work(*arguments)

def do_many(x, y, zs):
    map(do_one, [(x, y, z) for z in zs])

def do_many_pooled(x, y, zs):
    pool = Pool(2)
    pool.map(do_one, [(x, y, z) for z in zs])
    pool.close()
    pool.join()

def main():
    x = 1
    y = 2
    zs = range(10)
    print "doing many"
    do_many(x, y, zs)
    print "doing many pooled"
    do_many_pooled(x, y, zs)


if __name__ == '__main__':
    main()

真正的程序执行大量数据库请求,使用numpy进行计算并将结果存储回数据库。 在实际程序中,程序在打印“执行一个”之前退出并出现错误,当与池版本一起使用时,但使用非池化版本运行正常。

有谁知道,如何正确读取Traceback和/或可以告诉我,可能导致此异常的原因是什么?

1 个答案:

答案 0 :(得分:2)

我说这看起来好像put被设置为无关 追溯:

File "/usr/lib64/python2.7/multiprocessing/pool.py", line 342, in _handle_tasks
   put(task)
TypeError: 'NoneType' object is not callable

查看Python源代码,Pool.__init__()正在设置_task_handler 这将调用_handle_tasks并提供参数 电话说:

self._task_handler = threading.Thread(
    target=Pool._handle_tasks,
    args=(self._taskqueue, self._quick_put, self._outqueue, self._pool)
    )

如果您查看_handle_tasks,那么您会看到self._quick_put结束了 成为put变量:

@staticmethod
def _handle_tasks(taskqueue, put, outqueue, pool, cache):
    thread = threading.current_thread()

    for taskseq, set_length in iter(taskqueue.get, None):
        i = -1
        for i, task in enumerate(taskseq):
            if thread._state:
                debug('task handler found thread._state != RUN')
                break
            try:
                put(task)
            except Exception as e:
                job, ind = task[:2]
                try:
                    cache[job]._set(ind, (False, e))
                except KeyError:
                    pass
        else:
            if set_length:
                debug('doing set_length()')
                set_length(i+1)
            continue
        break
    else:
        debug('task handler got sentinel')

此外,您可以看到所有异常都被捕获并隐藏起来 稍后报告。但是,如果你回到Python 2.7.6,你会看到这个:

@staticmethod
def _handle_tasks(taskqueue, put, outqueue, pool):
    thread = threading.current_thread()

    for taskseq, set_length in iter(taskqueue.get, None):
        i = -1
        for i, task in enumerate(taskseq):
            if thread._state:
                debug('task handler found thread._state != RUN')
                break
            try:
                put(task)
            except IOError:
                debug('could not put task on queue')
                break
        else:
            if set_length:
                debug('doing set_length()')
                set_length(i+1)
            continue
        break
    else:
        debug('task handler got sentinel')

请注意,TypeError可以逃脱。事实证明这是固定的 由于bug #19425。奇怪的是,它是 声称这不是Python 2.7中的问题,但变更集仍然存在 反向移植。

无论如何,在任何一种情况下,put()都应该是一个已知值,并且没有 似乎是在此代码中设置put的任何方式。所以,对我来说,它闻起来像一个臭虫 在Python中。你有可能在更新的版本下运行相同的代码 蟒?

其他一些有用的信息

快速Google搜索也会返回一些有趣的结果:

  • Python bug #9755 - 类似但不同 堆栈跟踪。

  • Python bug #15881 - 与上述类似, 但是堆栈跟踪也略有不同。

两者都是清理影响模块状态并导致事情发生的问题 失败的"' NoneType'对象不可调用"异常。

其他有些相关的错误也存在于Python中。有一点你可以 使用守护程序线程并退出时会遇到类似的异常 您的应用程序的主线程。我忘了修复了哪个版本。我 只是想表明这种问题闻所未闻并且是一个错误 蟒。