concurrent.futures.ProcessPoolExecutor 当函数是 lambda 或嵌套函数时挂起
concurrent.futures.ProcessPoolExecutor hangs when the function is a lambda or nested function
谁能深入了解为什么使用 lambda 或嵌套函数 (f
) 会使 concurrent.futures.ProcessPoolExecutor
在以下代码示例中挂起?
import concurrent.futures
def f2(s):
return len(s)
def main():
def f(s):
return len(s)
data = ["a", "b", "c"]
with concurrent.futures.ProcessPoolExecutor(max_workers=1) as pool:
# results = pool.map(f, data) # hangs
# results = pool.map(lambda d: len(d), data) # hangs
# results = pool.map(len, data) # works
results = pool.map(f2, data) # works
print(list(results))
if __name__ == "__main__":
main()
长话短说,Pool/ProcessPoolExecutor 两者都必须在将它们发送给工作人员之前将所有内容序列化。序列化(有时也称为酸洗)实际上是保存函数名称的过程,只有在 Pool 想要访问它时才能再次导入。为了让这个过程起作用,函数必须在顶层定义,因为嵌套函数不能被子函数导入
这就是出现以下错误的原因:
AttributeError: Can't pickle local object 'MyClass.mymethod.<locals>.mymethod'
为了避免这个问题,有一些我认为不可靠的解决方案。如果您可以灵活地使用其他软件包,pathos 是一个实际上 可行 的替代方案。例如,以下不会挂起:
import pathos
import os
class SomeClass:
def __init__(self):
self.words = ["a", "b", "c"]
def some_method(self):
def run(s):
return len(s)
return list(pool.map(run, self.words))
pool = pathos.multiprocessing.Pool(os.cpu_count())
print(SomeClass().some_method())
它确实会打印
[1, 1, 1]
谁能深入了解为什么使用 lambda 或嵌套函数 (f
) 会使 concurrent.futures.ProcessPoolExecutor
在以下代码示例中挂起?
import concurrent.futures
def f2(s):
return len(s)
def main():
def f(s):
return len(s)
data = ["a", "b", "c"]
with concurrent.futures.ProcessPoolExecutor(max_workers=1) as pool:
# results = pool.map(f, data) # hangs
# results = pool.map(lambda d: len(d), data) # hangs
# results = pool.map(len, data) # works
results = pool.map(f2, data) # works
print(list(results))
if __name__ == "__main__":
main()
长话短说,Pool/ProcessPoolExecutor 两者都必须在将它们发送给工作人员之前将所有内容序列化。序列化(有时也称为酸洗)实际上是保存函数名称的过程,只有在 Pool 想要访问它时才能再次导入。为了让这个过程起作用,函数必须在顶层定义,因为嵌套函数不能被子函数导入 这就是出现以下错误的原因:
AttributeError: Can't pickle local object 'MyClass.mymethod.<locals>.mymethod'
为了避免这个问题,有一些我认为不可靠的解决方案。如果您可以灵活地使用其他软件包,pathos 是一个实际上 可行 的替代方案。例如,以下不会挂起:
import pathos
import os
class SomeClass:
def __init__(self):
self.words = ["a", "b", "c"]
def some_method(self):
def run(s):
return len(s)
return list(pool.map(run, self.words))
pool = pathos.multiprocessing.Pool(os.cpu_count())
print(SomeClass().some_method())
它确实会打印
[1, 1, 1]