生成器何时转换为Dask中的列表?

时间:2016-03-03 08:19:01

标签: python dask

在Dask中,生成器何时转换为列表,或者它们通常是懒散地消耗? 例如,使用代码:

from collections import Counter
import numpy as np
import dask.bag as db

def foo(n):
    for _ in range(n):
        yield np.random.randint(10)

def add_to_count(acc, x):
    acc.update(x)
    return acc

def add(x,y):
    return x + y

b1 = db.from_sequence([1,2,3,4,5])
b2 = b1.map(foo)
result = b2.fold(add_to_count, add, Counter())

我得到以下输出,其中有生成器 已经(合理地)转换为名单供我检查:

>>> b2.compute()
[[5], [5, 6], [3, 6, 1], [5, 6, 6, 0], [5, 6, 6, 0, 3]]

虽然合理,但它与我通常期望生成器在Python中表现的方式不同,这可能需要显式转换为列表。

所以,在计算foldresult.compute())时, 是x的输入参数add_to_count 生成器,还是已经转换为列表?

我对列表很长的情况很感兴趣, 所以懒惰的评价更有效率,比方说, b1 = db.from_sequence([10**6]*10)

我猜我也可以用bag.frequencies来解决上述问题,但我对懒惰评估和有效减少有类似的担忧。

Dask的一个基本方面是我不是在闲聊,或者我只是在懒惰,我在哪里可以查看代码来自己解决这个问题?

1 个答案:

答案 0 :(得分:2)

不完全合适,但我会提供一个稍微不同的问题的答案:

Dask.bag为你添加了对list的防御性调用,以防万一你决定分出并在一次计算中使用该包两次:

x = b.map(func1, b)
y = b.map(func2, b)
compute(x.frequencies(), b.frequencies())

这在使用多处理或分布式后端时也很有用,因为我们无法跨进程边界发送生成器,但可以发送列表。

但是,这些对list的防御性调用会在计算之前进行优化,以便在可能的情况下促进懒惰。

总之,一切都应该以正常的方式工作,但是当懒惰妨碍正确时,它将恢复为具体的非惰性值。