说我有以下简单的课程(很容易腌制):

import time
from concurrent.futures import ProcessPoolExecutor

class A:
    def long_computation(self):
        time.sleep(10)
        return 42


我希望能够做到这一点:

a = A()

with ProcessPoolExecutor(1) as executor:
    a.future = executor.submit(a.long_computation)


在Python 3.6.9上,此操作失败,并显示TypeError: can't pickle _thread.RLock objects。在3.8.0上,它导致无休止的等待获取锁的等待。

在两个版本上都起作用的是:

a = A()

with ProcessPoolExecutor(1) as executor:
    future = executor.submit(a.long_computation)
    time.sleep(0.001)
    a.future = future


在我看来,executor.submit阻塞的时间不足以完成对a的酸洗,并且在酸洗所得的Future对象时遇到问题。

我对time.sleep(0.001)解决方法不太满意,因为它涉及一个魔术数字,而且我认为如果酸洗的时间更长,则很容易失败。我不想睡​​更安全,更长的时间,因为那将是浪费。理想情况下,我希望executor.submit阻塞,直到可以安全地在Future中存储对a对象的引用为止。

有一个更好的方法吗?

最佳答案

再考虑一下,我想到了以下几点:

import pickle

a = A()

with ProcessPoolExecutor(1) as executor:
    a.future = executor.submit(pickle.loads(pickle.dumps(a)).long_computation)


由于对a进行了两次酸洗,因此涉及到重复的工作,但是效果很好,并且可以确保在任何情况下都不会根据需要对Future对象进行酸洗。

然后,我意识到这样做有效的原因是它创建了a的副本。因此,可以通过在提交方法之前简单地(浅)复制对象来避免进行酸洗和酸洗,从而确保副本上不存在对Future对象的引用:

from copy import copy

a = A()

with ProcessPoolExecutor(1) as executor:
    a.future = executor.submit(copy(a).long_computation)


与上面的泡菜周期相比,这更快且不那么尴尬,但是我仍然对这里的最佳做法感兴趣,因此我将稍等一下再接受这个答案。

关于python - 确保在ProcessPoolExecutor.submit返回之前完成酸洗,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59141018/

10-10 19:10