说我有以下简单的课程(很容易腌制):
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/