perl6“首先等待的操作”

Posted

技术标签:

【中文标题】perl6“首先等待的操作”【英文标题】:perl6 "An operation first awaited" 【发布时间】:2018-11-07 11:21:36 【问题描述】:

该程序创建一个线程来使用 dir() 读取目录并将文件放在通道上。 $N 个工作线程读取该通道并“处理”(打印)文件。

但是我得到了这个“首先等待的操作:”错误。

我已多次阅读有关此错误的陷阱页面,但仍然无法理解。有人能解释一下这里发生了什么吗?

目录内容:

$ ls a b c traverse-dir0.p6

运行程序:

$ ./traverse-dir0.p6 遍历-dir0.p6 一种 b C 首先等待一个操作: 在 ./traverse-dir0.p6 第 24 行的子 MAIN 中 在 ./traverse-dir0.p6 第 5 行的块中 死于异常: 找不到方法“路径”:没有方法缓存,也没有 .^find_method 在 ./traverse-dir0.p6 第 16 行的块中

程序遍历-dir0.p6:

#!/usr/bin/env perl6 # 有一个线程通过使用 dir() 读取目录中的文件名来填充 $dir-channel # 和 $N 工作线程从 $dir 通道读取文件名。 子主(Str $dir =“。”,Int:$N = 4) 我的 $dir-channel = Channel.new(); 我的 $dir-read = 开始 $dir-channel.send( $_ ) for dir $dir; $dir-channel.close; 我的@workers = (^$N).map: 开始 而我的 $file = $dir-channel.receive() 说 $file.path; 抓住 当 X::Channel::ReceiveOnClosed .resume 等待 $dir-read, @workers;

【问题讨论】:

基础错误是Cannot find method 'path': no method cache and no .^find_method。修复该错误,看看会发生什么 你为什么这么关注“An operation first awaited”(这只是一个句子片段,完整的句子是“An operation(that was first waiting in [location])死了,但例外: “)?错误是Cannot find method 'path' 事后看来,我本可以更好地分阶段提出这个问题。但是我更感兴趣的是流控制如何到达“找不到方法'路径'”,即
say $file.path;
行。为什么 .resume 在
while my $file = $dir-channel.receive()
循环
【参考方案1】:

首先,关于await 引发的异常的输出。当异步操作失败时,有两条有趣的信息:

我们希望在程序中的哪个位置得到运算结果 问题出现在程序的哪个位置,意味着操作无法执行

第一条信息指示await 的位置,堆栈跟踪与此相关。第二部分为await重新抛出异常的原因,并指出需要修复的问题。

在这种情况下的问题是path 方法是在一个没有对象的对象上调用的。这要感谢.resume,这是没有意义的。抛出异常表示无法从通道接收值。恢复它只是意味着循环体以$file 中的未定义值运行,它缺少path 方法并导致错误。 (顺便说一句:.resume 是正确答案的情况非常非常罕见。)

对代码的最小修复是将.resume替换为last,这会在通道关闭时终止迭代:

my @workers = (^$N).map: 
    start 
        while my $file = $dir-channel.receive() 
            say $file.path;
            CATCH 
                when X::Channel::ReceiveOnClosed  last 
            
        
    

但是,将Channel 强制转换为可迭代的Seq 要简单得多。这会在 Channel 关闭时自动处理终止迭代,因此不会出现异常:

my @workers = (^$N).map: 
    start 
        for $dir-channel.Seq -> $file 
            say $file.path;
        
    

由于start 是一个语句前缀,因此进一步缩短为:

my @workers = (^$N).map: 
    start for $dir-channel.Seq -> $file 
        say $file.path;
       
   

我很欣赏这可能是一个更有趣问题的简化版本,或者可能是为了探索各种 Perl 6 并发概念,但全部内容可以替换为:

sub MAIN( Str $dir = ".", Int :$N = 4 ) 
    race for dir($dir).race(batch => 1, degree => $N) -> $file 
        say $file.path;
    

这具有相同的语义,但省去了启动和管理工作人员,同时仍然控制工作人员的数量并确保文件在工作人员之间以相同的方式分布。

【讨论】:

非常好的简化,谢谢!我遇到的主要问题是不了解 .resume 以及流控制恢复到的位置。 它恢复到引发异常的地方 - 在这种情况下,在 Channel 实现内部的某个地方。 对原始版本的另一个修复似乎是省略了.resume。即:when X::Channel::ReceiveOnClosed 。这将是我对.resume 的预期行为,该控件将作为失败返回$dir-channel.receive(),因此退出while。无论如何,提供的解决方案更易于使用。

以上是关于perl6“首先等待的操作”的主要内容,如果未能解决你的问题,请参考以下文章

perl6正则 2: 字母,数字,空格和下划线

将包转换为 perl6

Perl6 中的类型强制

perl6文件操作

perl6中的hash定义

是否可以将 perl6 嵌入到 C(或 C++)程序中?