未检测到多处理池中引发的异常
似乎当 multiprocessing.Pool 进程引发异常时,没有堆栈跟踪或任何其他指示它已失败。示例:
from multiprocessing import Pool
def go():
print(1)
raise Exception()
print(2)
p = Pool()
p.apply_async(go)
p.close()
p.join()
打印 1 并安静地停止。有趣的是,引发 BaseException 反而有效。有什么方法可以使所有异常的行为与 BaseException 相同吗?
It seems that when an exception is raised from a multiprocessing.Pool process, there is no stack trace or any other indication that it has failed. Example:
from multiprocessing import Pool
def go():
print(1)
raise Exception()
print(2)
p = Pool()
p.apply_async(go)
p.close()
p.join()
prints 1 and stops silently. Interestingly, raising a BaseException instead works. Is there any way to make the behavior for all exceptions the same as BaseException?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
也许我遗漏了一些东西,但这不是 Result 对象的
get
方法返回的内容吗?请参阅进程池。因此,稍微修改一下你的例子,就可以做
这给出的结果
这并不完全令人满意,因为它不打印回溯,但总比没有好。
更新:此错误已在 Python 3.4 中修复,由 Richard Oudkerk 提供。请参阅问题multiprocessing.pool.Async 的 get 方法应返回完整的回溯。
Maybe I'm missing something, but isn't that what the
get
method of the Result object returns? See Process Pools.So, slightly modifying your example, one can do
Which gives as result
This is not completely satisfactory, since it does not print the traceback, but is better than nothing.
UPDATE: This bug has been fixed in Python 3.4, courtesy of Richard Oudkerk. See the issue get method of multiprocessing.pool.Async should return full traceback.
我对这个问题有一个合理的解决方案,至少出于调试目的。我目前没有解决方案可以在主流程中引发异常。我的第一个想法是使用装饰器,但你只能 pickle 在模块顶层定义的函数,所以这是正确的。
相反,一个简单的包装类和一个 Pool 子类将其用于
apply_async
(因此apply
)。我将把map_async
留给读者作为练习。这给了我:
I have a reasonable solution for the problem, at least for debugging purposes. I do not currently have a solution that will raise the exception back in the main processes. My first thought was to use a decorator, but you can only pickle functions defined at the top level of a module, so that's right out.
Instead, a simple wrapping class and a Pool subclass that uses this for
apply_async
(and henceapply
). I'll leavemap_async
as an exercise for the reader.This gives me:
在撰写本文时获得最多票数的解决方案有一个问题:
正如 @dfrankow 指出的那样,它将等待 x.get(),这破坏了异步运行任务的意义。因此,为了提高效率(特别是如果您的辅助函数
go
需要很长时间),我会将其更改为:优点:辅助函数是异步运行的,因此如果例如,您在多个内核上运行许多任务,它将比原始解决方案效率更高。
缺点:如果工作函数中存在异常,只有在池完成所有任务后才会引发异常。这可能是也可能不是理想的行为。根据@colinfang的评论进行编辑,修复了这个问题。The solution with the most votes at the time of writing has a problem:
As @dfrankow noted, it will wait on
x.get()
, which ruins the point of running a task asynchronously. So, for better efficiency (in particular if your worker functiongo
takes a long time) I would change it to:Advantages: the worker function is run asynchronously, so if for example you are running many tasks on several cores, it will be a lot more efficient than the original solution.
Disadvantages: if there is an exception in the worker function, it will only be raised after the pool has completed all the tasks. This may or may not be the desirable behaviour.EDITED according to @colinfang's comment, which fixed this.由于
multiprocessing.Pool
已经有了不错的答案,因此我将使用不同的方法提供一个解决方案以保证完整性。对于
python >= 3.2
,以下解决方案似乎是最简单的:优点:
项 有关 API 的更多信息,请查看这个
此外,如果您要提交一个大型任务数,并且您希望主进程在其中一个任务失败时立即失败,您可以使用以下代码片段:
只有在执行所有任务后,所有其他答案才会失败。
Since there are already decent answers for
multiprocessing.Pool
available, I will provide a solution using a different approach for completeness.For
python >= 3.2
the following solution seems to be the simplest:Advantages:
For more info about the API please check out this
Additionally, if you are submitting a large number of tasks and you would like your main process to fail as soon as one of your tasks fail, you can use the following snippet:
All of the other answers fail only once all tasks have been executed.
我已经用这个装饰器成功记录了异常:
使用问题中的代码,它
只是装饰您传递给进程池的函数。这项工作的关键是@functools.wraps(func),否则多重处理会抛出PicklingError。
上面的代码给出了
I've had success logging exceptions with this decorator:
with the code in the question, it's
Simply decorate the function you pass to your process pool. The key to this working is
@functools.wraps(func)
otherwise multiprocessing throws aPicklingError
.code above gives
由于您已经使用了
apply_sync
,我猜用例是想要执行一些同步任务。使用回调进行处理是另一种选择。请注意,此选项仅适用于 python3.2 及以上版本,不适用于 python2.7。Since you have used
apply_sync
, I guess the use case is want to do some synchronize tasks. Use callback for handling is another option. Please note this option is available only for python3.2 and above and not available on python2.7.我创建了一个模块 RemoteException.py,它显示进程中异常的完整回溯。 Python2。 下载并将其添加到您的代码中:
I created a module RemoteException.py that shows the full traceback of a exception in a process. Python2. Download it and add this to your code:
我会尝试使用 pdb:
I'd try using pdb: