我确实有一个程序,它已经使用了很长一段时间,但它已经被使用和工作了。它使用多处理,因为必须多次对不同的数据执行相同的任务。
我现在触摸了程序添加一个新参数,测试它并注意到它出现了错误。此外,早期(版本控制)版本也会出现相同的错误。完整错误如下所示:
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和/或可以告诉我,可能导致此异常的原因是什么?
答案 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搜索也会返回一些有趣的结果:
两者都是清理影响模块状态并导致事情发生的问题 失败的"' NoneType'对象不可调用"异常。
其他有些相关的错误也存在于Python中。有一点你可以 使用守护程序线程并退出时会遇到类似的异常 您的应用程序的主线程。我忘了修复了哪个版本。我 只是想表明这种问题闻所未闻并且是一个错误 蟒。