API

API

dask.delayed 接口由一个函数 delayed 组成:

  • delayed 包装函数

    包装函数。可以用作装饰器,或直接在函数调用周围使用(即 delayed(foo)(a, b, c))。由 delayed 包装的函数的输出是 Delayed 类型的代理对象,其中包含为得到此结果所做的所有操作的图。

  • delayed 包装对象

    包装对象。用于直接创建 Delayed 代理。

Delayed 对象可以被视为 dask 任务图中的一个键。Delayed 支持 大多数 Python 操作,每个操作都会创建另一个代表结果的 Delayed

  • 大多数操作符(*``-``等)

  • 项目访问和切片 (a[0])

  • 属性访问 (a.size)

  • 方法调用 (a.index(0))

不支持的操作包括:

  • 变异操作符 (a += 1)

  • 诸如 __setitem__/__setattr__ 的变异魔法(例如 a[0] = 1, a.foo = 1

  • 迭代。(for i in a: ...

  • 作为谓词使用 (if a: ...)

最后两点尤其意味着 Delayed 对象不能用于控制流程,这意味着循环或 if 语句中不能出现 Delayed 。换句话说,你不能迭代 Delayed 对象,或者在 if 语句的条件中使用它,但 Delayed 对象可以在循环或 if 语句的主体中使用(即上面的例子是可以的,但如果 data 是一个 Delayed 对象则不行)。尽管有这个限制,许多工作流程仍然可以轻松并行化。

delayed([obj, name, pure, nout, traverse])

将一个函数或对象包装起来,生成一个 Delayed

Delayed(key, dsk[, length, layer])

表示一个由 dask 计算的值。

dask.delayed.delayed(obj='__no__default__', name=None, pure=None, nout=None, traverse=True)[源代码]

将一个函数或对象包装起来,生成一个 Delayed

Delayed 对象充当它们所包装对象的代理,但所有对它们进行的操作都是通过内部构建一个 dask 图来延迟执行的。

参数
obj对象

要包装的函数或对象

名称Dask 键, 可选

用于底层图表中包装对象的关键字。默认为哈希内容。请注意,这仅影响此延迟调用所包装的对象名称,而不会影响延迟函数调用的输出 - 为此,请使用下面描述的 dask_key_name=

备注

因为这个 name 在任务图中被用作键,你应该确保它唯一标识 obj 。如果你想提供一个描述性的名称,同时确保其唯一性,可以将描述性名称与 dask.base.tokenize()array_like 结合起来。更多信息请参见 任务图

bool, 可选

指示调用生成的 Delayed 对象是否是一个纯操作。如果为 True,调用的参数将被哈希以生成确定性的键。如果未提供,默认值是检查全局的 delayed_pure 设置,如果未设置则回退到 False

noutint, 可选

调用生成的 Delayed 对象返回的输出数量。如果提供,调用的 Delayed 输出可以迭代为 nout 个对象,允许结果解包。默认情况下,迭代 Delayed 对象会出错。注意,nout=1 期望 obj 返回一个长度为1的元组,因此对于 nout=0obj 应该返回一个空元组。

遍历bool, 可选

默认情况下,dask 会遍历内置的 Python 集合,查找传递给 delayed 的 dask 对象。对于大型集合,这可能会很耗费资源。如果 obj 不包含任何 dask 对象,请设置 traverse=False 以避免进行此遍历。

示例

应用于函数以延迟执行:

>>> from dask import delayed
>>> def inc(x):
...     return x + 1
>>> inc(10)
11
>>> x = delayed(inc, pure=True)(10)
>>> type(x) == Delayed
True
>>> x.compute()
11

可以用作装饰器:

>>> @delayed(pure=True)
... def add(a, b):
...     return a + b
>>> add(1, 2).compute()
3

delayed 也接受一个可选的关键字 pure。如果为 False,那么后续调用将始终产生不同的 Delayed。这对于非纯函数(如 timerandom)非常有用。

>>> from random import random
>>> out1 = delayed(random, pure=False)()
>>> out2 = delayed(random, pure=False)()
>>> out1.key == out2.key
False

如果你知道一个函数是纯函数(输出仅依赖于输入,没有全局状态),那么你可以设置 pure=True。这将尝试为输出应用一个一致的名称,但如果失败,将回退到 pure=False 的相同行为。

>>> @delayed(pure=True)
... def add(a, b):
...     return a + b
>>> out1 = add(1, 2)
>>> out2 = add(1, 2)
>>> out1.key == out2.key
True

除了将 pure 设置为可调用对象的属性外,您还可以使用 delayed_pure 设置在上下文中设置它。请注意,这会影响 调用 而不是 创建 可调用对象:

>>> @delayed
... def mul(a, b):
...     return a * b
>>> import dask
>>> with dask.config.set(delayed_pure=True):
...     print(mul(1, 2).key == mul(1, 2).key)
True
>>> with dask.config.set(delayed_pure=False):
...     print(mul(1, 2).key == mul(1, 2).key)
False

调用延迟对象的结果的键名默认由参数的哈希值决定。要显式设置名称,可以在调用函数时使用 dask_key_name 关键字:

>>> add(1, 2)   
Delayed('add-3dce7c56edd1ac2614add714086e950f')
>>> add(1, 2, dask_key_name='three')
Delayed('three')

请注意,具有相同键名的对象被假定为具有相同的结果。如果你明确设置了名称,你应该确保不同结果的键名是不同的。

>>> add(1, 2, dask_key_name='three')
Delayed('three')
>>> add(2, 1, dask_key_name='three')
Delayed('three')
>>> add(2, 2, dask_key_name='four')
Delayed('four')

delayed 也可以应用于对象,使对它们进行的操作变为惰性操作:

>>> a = delayed([1, 2, 3])
>>> isinstance(a, Delayed)
True
>>> a.compute()
[1, 2, 3]

如果 pure=True,延迟对象的键名默认会被哈希;如果 pure=False``(默认),键名会随机生成。要显式设置名称,可以使用 ``name 关键字。为了确保键名唯一,你应该同时包含标记化的值,或者确保其唯一性:

>>> from dask.base import tokenize
>>> data = [1, 2, 3]
>>> a = delayed(data, name='mylist-' + tokenize(data))
>>> a  
Delayed('mylist-55af65871cb378a4fa6de1660c3e8fb7')

延迟结果作为底层对象的代理。支持许多操作符:

>>> (a + [1, 2]).compute()
[1, 2, 3, 1, 2]
>>> a[1].compute()
2

方法和属性访问也同样有效:

>>> a.count(2).compute()
1

请注意,如果一个方法不存在,直到运行时才会抛出错误:

>>> res = a.not_a_real_method() 
>>> res.compute()  
AttributeError("'list' object has no attribute 'not_a_real_method'")

“魔法”方法(例如操作符和属性访问)被假定为纯函数,意味着后续调用必须返回相同的结果。这种行为不能通过 delayed 调用来覆盖,但可以通过以下描述的其他方式进行修改。

要调用一个非纯属性或操作符,你需要在一个带有 pure=False 的延迟函数中使用它:

>>> class Incrementer:
...     def __init__(self):
...         self._n = 0
...     @property
...     def n(self):
...         self._n += 1
...         return self._n
...
>>> x = delayed(Incrementer())
>>> x.n.key == x.n.key
True
>>> get_n = delayed(lambda x: x.n, pure=False)
>>> get_n(x).key == get_n(x).key
False

相比之下,方法默认被认为是非纯的,这意味着后续调用可能会返回不同的结果。要假设纯度,请设置 pure=True。这允许共享任何中间值。

>>> a.count(2, pure=True).key == a.count(2, pure=True).key
True

与函数调用一样,方法调用也遵循全局的 delayed_pure 设置,并支持 dask_key_name 关键字:

>>> a.count(2, dask_key_name="count_2")
Delayed('count_2')
>>> import dask
>>> with dask.config.set(delayed_pure=True):
...     print(a.count(2).key == a.count(2).key)
True
class dask.delayed.Delayed(key, dsk, length=None, layer=None)[源代码]

表示一个由 dask 计算的值。

相当于dask图中单个键的输出。