role Iterable { }

Iterable 作为可使用 for 和相关迭代构造(如赋值给 Positional 变量)进行迭代的对象的 API。

嵌套在其他 Iterable 对象中的 Iterable 对象(但不在标量容器中)在某些上下文中会扁平化,例如传递给 slurpy 参数 (*@a) 时,或显式调用 flat 时。

它最重要的方面是 iterator 的方法存根。

class DNA does Iterable {
    has $.chain;
    method new ($chain where { $chain ~~ /^^ <[ACGT]>+ $$ / } ) {
        self.bless:$chain );
    }
 
    method iterator(DNA:D:{
        $!chain.comb.rotor(3).iterator;
    }
}
 
my $a := DNA.new('GAATCC');
.say for $a# OUTPUT: «(G A A)␤(T C C)␤» 

此示例混合了 Iterable 角色,以提供一种新的方式来迭代本质上是字符串的内容(由 where 约束为仅四个 DNA 字母)。在最后一条语句中,for 实际上连接到 iterator 角色,以 3 组的形式打印字母。

方法§

方法迭代器§

method iterator(--> Iterator:D)

方法存根,确保所有执行 Iterable 角色的类都有一个方法 iterator

它应该返回一个 Iterator

say (1..10).iterator;

方法扁平化§

method flat(Iterable:D: --> Iterable)

返回另一个 Iterable,它将第一个 Iterable 返回的所有可迭代项扁平化。

例如

say (<a b>'c').elems;         # OUTPUT: «2␤» 
say (<a b>'c').flat.elems;    # OUTPUT: «3␤»

因为 <a b> 是一个 List,因此可迭代,所以 (<a b>, 'c').flat 返回 ('a', 'b', 'c'),它有三个元素。

请注意,扁平化是递归的,因此 ((("a", "b"), "c"), "d").flat 返回 ("a", "b", "c", "d"),但它不会扁平化项目化的子列表

say ($('a''b'), 'c').flat;    # OUTPUT: «($("a", "b"), "c")␤»

您可以使用 超方法调用 对所有内部项目化子列表调用 .List 方法,从而取消它们的容器化,以便 flat 可以扁平化它们

say ($('a''b'), 'c')>>.List.flat.elems;    # OUTPUT: «3␤»

方法惰性§

method lazy(--> Iterable)

返回一个惰性可迭代项,包装调用方。

say (1 ... 1000).is-lazy;      # OUTPUT: «False␤» 
say (1 ... 1000).lazy.is-lazy# OUTPUT: «True␤»

方法超§

method hyper(Int(Cool:$batch = 64Int(Cool:$degree = 4)

返回另一个 Iterable,它可能以并行方式迭代,具有给定的批处理大小和并行度。

元素的顺序将被保留。

say ([1..100].hyper.map({ $_ +1 }).list);

在可以并行处理项目并且输出顺序应相对于输入顺序保持不变的情况下使用 hyper。有关并行处理项目且输出顺序无关紧要的情况,请参见 race

选项度和批处理§

degree 选项(“并行度”的缩写)配置应启动多少并行工作进程。要启动 4 个工作进程(例如,最多使用 4 个内核),请将 :4degree 传递给 hyperrace 方法。请注意,在某些情况下,选择高于可用 CPU 内核的度数是有意义的,例如 I/O 绑定工作或 Web 爬取等延迟繁重的任务。但是,对于 CPU 绑定工作,选择高于 CPU 内核数的数字是没有意义的。

batch 大小选项配置一次发送到给定并行工作进程的项目数。它允许进行吞吐量/延迟权衡。例如,如果每个项目的操作是长时间运行的,并且您需要尽快获得第一个结果,请将其设置为 1。这意味着每个并行工作进程一次获取 1 个项目进行处理,并尽快报告结果。因此,线程间通信的开销最大化。在另一个极端情况下,如果您有 1000 个项目要处理且有 10 个工作进程,并且您给每个工作进程分配 100 个项目的批处理,那么您将为分派项目产生最小的开销,但您只有在最快的进程处理 100 个项目(或对于 hyper,当获取第一个批处理的工作进程返回时)才能获得第一个结果。此外,如果并非所有项目都需要相同的时间来处理,您可能会遇到某些工作进程已经完成并且无法帮助完成剩余工作的情况。在并非所有项目都需要相同的时间来处理且您不希望线程间通信开销过大的情况下,选择介于两者之间的数字是有意义的。您的目标可能是让所有工作进程都保持均匀繁忙,以便充分利用可用资源。

您还可以查看此有关 hyper 和 race 语义的博客文章

从 Rakudo 编译器的 2022.07 版本开始,还可以指定未定义的值以指示使用默认值。

method race§

method race(Int(Cool:$batch = 64Int(Cool:$degree = 4 --> Iterable)

返回另一个 Iterable,该 Iterable 可能并行迭代,具有给定的批处理大小和并行度(并行工作进程数)。

hyper 不同,race 不保留元素的顺序(助记符:在比赛中,你永远不知道谁会先到达)。

say ([1..100].race.map({ $_ +1 }).list);

在可以并行处理项目并且输出顺序无关紧要的情况下使用 race。有关您希望并行处理项目且输出顺序应相对于输入顺序保持不变的情况,请参见 hyper

有关 hyper 和 race 语义的博客文章

有关 :$batch:$degree 的说明,请参见 hyper

Typegraph§

Iterable 的类型关系
raku-type-graph Iterable Iterable Mu Mu Any Any Any->Mu Cool Cool Cool->Any Positional Positional Range Range Range->Iterable Range->Cool Range->Positional PositionalBindFailover PositionalBindFailover Sequence Sequence Sequence->PositionalBindFailover Seq Seq Seq->Iterable Seq->Cool Seq->Sequence List List List->Iterable List->Cool List->Positional RaceSeq RaceSeq RaceSeq->Iterable RaceSeq->Any RaceSeq->Sequence Associative Associative IO::Path::Parts IO::Path::Parts IO::Path::Parts->Iterable IO::Path::Parts->Any IO::Path::Parts->Positional IO::Path::Parts->Associative Map Map Map->Iterable Map->Cool Map->Associative HyperSeq HyperSeq HyperSeq->Iterable HyperSeq->Any HyperSeq->Sequence Slip Slip Slip->List Array Array Array->List PseudoStash PseudoStash PseudoStash->Map Hash Hash Hash->Map Stash Stash Stash->Hash

展开上面的图表