为什么 dict 没有在 dask 中发生突变?
Why is the dict not mutated in dask?
How does dask.delayed handle mutable inputs?用delayed
解释了但是如果我需要改变输入怎么办?
我一直在试用 Dask,我需要了解使用 distributed.Client.get
与顺序(正常方式)调用时字典是如何发生变化的。
顺序
def foo(dictionary):
dictionary['foo'] = 'foo was called'
def bar(dictionary):
dictionary['bar'] = 'bar was called'
dictionary = {}
print(dictionary) # {}
foo(dictionary)
print(dictionary) # {'foo': 'foo was called'}
bar(dictionary)
print(dictionary) # {'foo': 'foo was called', 'bar': 'bar was called'}
这按我预期的方式工作,字典发生了变化,在调用 foo
和 bar
.
后我得到了两个键
达斯克
from dask.distributed import Client
client = Client(processes=False)
def foo(dictionary):
dictionary['foo'] = 'foo was called'
def bar(dictionary):
dictionary['bar'] = 'bar was called'
dictionary = {}
dsk = {'foo': (foo, dictionary), 'bar':(bar, dictionary)}
client.get(dsk, ['foo', 'bar'])
print(dictionary) # {}
为什么这会返回一个空字典?为什么那没有变异?我注意到 dictionary
字典在每个函数中有不同的 id(dictionary)
,所以我知道它是一个副本。
假设每个函数都有自己的传递给它的对象的副本是否安全?所以我可以在函数内改变它们并让全局的那个保持不变?这个理解对吗?
简短的回答:当你打包一个图并将它发送到调度器,然后调度器将它发送给工作人员时,图会被序列化然后反序列化。本质上,它是在假设调度程序和工作程序位于另一个进程或机器中的情况下编写的。
这会创建新副本,因此突变对原始副本没有影响。我相信对于 pickle5,更大的类似缓冲区的对象(例如数组)可能是零拷贝的。
使用默认线程调度程序,图表只是交给调度程序,不会复制任何内容。这是一种简单得多的机制,也是一种简单得多的调度程序实现,但它仍然有其用途。
要实际改变对象,您需要使用变量(不适用于大型对象,它们存在于调度程序中)、参与者(小众用例)或共享内存。在任何情况下,它都会打破正常的 dask“功能性”假设,即任务的结果取决于其输入,并且您需要小心处理任务可能被调用两次的情况。
How does dask.delayed handle mutable inputs?用delayed
解释了但是如果我需要改变输入怎么办?
我一直在试用 Dask,我需要了解使用 distributed.Client.get
与顺序(正常方式)调用时字典是如何发生变化的。
顺序
def foo(dictionary):
dictionary['foo'] = 'foo was called'
def bar(dictionary):
dictionary['bar'] = 'bar was called'
dictionary = {}
print(dictionary) # {}
foo(dictionary)
print(dictionary) # {'foo': 'foo was called'}
bar(dictionary)
print(dictionary) # {'foo': 'foo was called', 'bar': 'bar was called'}
这按我预期的方式工作,字典发生了变化,在调用 foo
和 bar
.
达斯克
from dask.distributed import Client
client = Client(processes=False)
def foo(dictionary):
dictionary['foo'] = 'foo was called'
def bar(dictionary):
dictionary['bar'] = 'bar was called'
dictionary = {}
dsk = {'foo': (foo, dictionary), 'bar':(bar, dictionary)}
client.get(dsk, ['foo', 'bar'])
print(dictionary) # {}
为什么这会返回一个空字典?为什么那没有变异?我注意到 dictionary
字典在每个函数中有不同的 id(dictionary)
,所以我知道它是一个副本。
假设每个函数都有自己的传递给它的对象的副本是否安全?所以我可以在函数内改变它们并让全局的那个保持不变?这个理解对吗?
简短的回答:当你打包一个图并将它发送到调度器,然后调度器将它发送给工作人员时,图会被序列化然后反序列化。本质上,它是在假设调度程序和工作程序位于另一个进程或机器中的情况下编写的。 这会创建新副本,因此突变对原始副本没有影响。我相信对于 pickle5,更大的类似缓冲区的对象(例如数组)可能是零拷贝的。
使用默认线程调度程序,图表只是交给调度程序,不会复制任何内容。这是一种简单得多的机制,也是一种简单得多的调度程序实现,但它仍然有其用途。
要实际改变对象,您需要使用变量(不适用于大型对象,它们存在于调度程序中)、参与者(小众用例)或共享内存。在任何情况下,它都会打破正常的 dask“功能性”假设,即任务的结果取决于其输入,并且您需要小心处理任务可能被调用两次的情况。