Python 调用dask Client.map()时会发生什么?
我正在尝试使用dask编写一个网格搜索实用程序。目标函数调用包含大量数据的类的方法。我试图使用dask将计算并行化到多核心解决方案,而不必复制原始类/数据帧。我在文档中没有找到任何解决方案,因此我在这里发布了一个玩具示例:Python 调用dask Client.map()时会发生什么?,python,mapreduce,dask,Python,Mapreduce,Dask,我正在尝试使用dask编写一个网格搜索实用程序。目标函数调用包含大量数据的类的方法。我试图使用dask将计算并行化到多核心解决方案,而不必复制原始类/数据帧。我在文档中没有找到任何解决方案,因此我在这里发布了一个玩具示例: import pickle from dask.distributed import Client, LocalCluster from multiprocessing import current_process class TestClass: def __i
import pickle
from dask.distributed import Client, LocalCluster
from multiprocessing import current_process
class TestClass:
def __init__(self):
self.param = 0
def __getstate__(self):
print("I am pickled!")
return self.__dict__
def loss(self, ext_param):
self.param += 1
print(f"{current_process().pid}: {hex(id(self))}: {self.param}: {ext_param} ")
return f"{self.param}_{ext_param}"
def objective_function(param):
return test_instance.loss(param)
if __name__ == '__main__':
test_instance = TestClass()
print(hex(id(test_instance)))
cluster = LocalCluster(n_workers=2)
client = Client(cluster)
futures = client.map(objective_function, range(20))
result = client.gather(futures)
print(result)
# ---- OUTPUT RESULTS ----
# 0x7fe0a5056d30
# I am pickled!
# I am pickled!
# 11347: 0x7fb9bcfa0588: 1: 0
# 11348: 0x7fb9bd0a2588: 1: 1
# 11347: 0x7fb9bcf94240: 1: 2
# 11348: 0x7fb9bd07b6a0: 1: 3
# 11347: 0x7fb9bcf945f8: 1: 4
# ['1_0', '1_1', '1_2', '1_3', '1_4']
我有以下问题:
test\u实例副本
,从每次迭代的不同类地址以及test\u实例.param
属性在每次迭代时都被设置为0这一事实可以看出这一点(这种行为不同于我强调的多处理池的标准实现)。我假设在每次迭代过程中,每个进程都会收到一个新的pickle类副本,对吗test_instance
副本?是否为1(对于主线程中的原始实例)+1(pickle copy)+2(每个进程中存在的实例)=4?是否有办法将该值设为1\uuuu main\uuuu
中,这可能不可靠,dask会退回到cloudpickle(它在内部也调用pickle)。在我看来,这就像检查是否在中一样distributed.protocol.pickle.dumps中的
可能在首次尝试pickle之前发生
在每次迭代过程中,每个进程都将收到一个新的pickle类副本
是的。每次dask运行任务时,它都会对输入进行反序列化,从而创建实例的nw副本。请注意,您的dask工作线程可能是通过fork_服务器技术创建的,因此不会简单地复制内存(这是安全的方法)
您可以在计算之前将实例“分散”给工作人员,他们可以重用其本地副本,但dask任务不应该通过改变对象而工作,而是通过返回结果(即功能上的)
内存中有多少个test_实例副本
客户端中为1,每个正在执行的任务加上一个。序列化版本也可能存在,可能一个保存在图形中,临时保存在客户端上,然后保存在计划程序上;在反序列化时,它也将临时保存在工作内存中。对于某些类型,零拷贝de/ser是可能的
如果由于对象的大小,任务非常大,那么您肯定应该事先“分散”它们(client.scatter
)
有没有办法把这个值设为1
您可以运行调度程序和/或进程中的工作者来共享内存,但是,当然,这样您就失去了与GIL的并行性
也许你可以试试?该模式似乎与你的工作流程相匹配。谢谢,这是一个很好的答案。你能给我指一些关于fork_服务器的信息吗?它与os.fork有什么不同吗?是的,不同: