当前位置: 首页 > 知识库问答 >
问题:

perl6"等待的操作"

储志业
2023-03-14

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

然而,我得到了这个“等待的第一个操作:”错误。

关于这个错误,我已经在陷阱页面上读了好几遍了,但还是没有弄明白。能解释一下这里发生了什么吗?

目录内容:

$ ls
a  b  c  traverse-dir0.p6

运行程序

$ ./traverse-dir0.p6 
traverse-dir0.p6
a
b
c
An operation first awaited:
  in sub MAIN at ./traverse-dir0.p6 line 24
  in block  at ./traverse-dir0.p6 line 5

Died with the exception:
    Cannot find method 'path': no method cache and no .^find_method
      in block  at ./traverse-dir0.p6 line 16

程序travers-dir. p6:

#!/usr/bin/env perl6
# There is a thread to populate $dir-channel by reading filenames in a directory with dir()
# and $N worker threads to read the filenames from the $dir-channel.

sub MAIN( Str $dir = ".", Int :$N = 4 ) {

    my $dir-channel = Channel.new();
    my $dir-read = start {
        $dir-channel.send( $_ ) for dir $dir;
        $dir-channel.close;
    }

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

    await $dir-read, @workers;
}

共有1个答案

鲜于凯康
2023-03-14

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

  • 在程序中,我们希望得到操作结果的位置

第一条信息指示wait的位置,堆栈跟踪与此相关。第二部分是关于wait重新引发异常的原因,并指出需要解决的问题。

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

对代码的最小修复是替换。使用最后一个继续,当频道关闭时终止迭代:

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

但是,将频道强制为可编辑的Seq要简单得多。当频道关闭时,这会自动处理终止迭代的问题,因此不会出现异常:

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;
    }
}

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

 类似资料:
  • 问题内容: 如何更改以下代码,以触发两个异步操作并有机会同时运行? 我需要做这样的事情吗? 问题答案: TL; DR 不要在获得承诺的问题中使用模式,而是分别等待它们;而是使用(至少现在): 虽然您的解决方案 确实 并行运行这两个操作,但如果两个诺言都被拒绝,它就无法正确处理拒绝。 细节: 您的解决方案并行运行它们,但始终等待第一个完成,然后再等待第二个。 如果您只想启动它们,并行运行它们,并获得

  • 问题内容: 我如何更改以下代码,以触发两个异步操作并有机会同时运行? 我需要做这样的事情吗? 问题答案: TL; DR 不要在获得承诺的问题中使用模式,而是分别等待它们;而是使用(至少现在): 虽然您的解决方案确实并行运行这两个操作,但是如果两个诺言都被拒绝,它就无法正确处理拒绝。 细节: 您的解决方案并行运行它们,但始终等待第一个完成,然后再等待第二个。如果您只想启动它们,并行运行它们,并获得两

  • 我可以让selenium webdriver“默认”等待它的每个操作执行吗?例如,设置任何“默认等待时间”,使其尝试每500毫秒点击每个元素10次?

  • 我已经实现了一个线程池。现在,它的基本操作如下: 空初始化(布尔detached_threads); bool调度(ulux(*dispatch_fn)(ulux), ulux arg, boolfree_arg); void shut\u down(); 静态无效*execute_task(无效*arg); 现在我想添加等待()操作,它将由主线程调用,并等待线程池中的所有线程完成它们正在执行的任

  • 启动C 20时,原子的操作有等待操作和通知操作。但我不知道它们到底是怎么工作的。cppreference说: 执行原子等待操作。表现为它重复执行以下步骤: 比较此的值表示形式- 这些函数保证仅在值发生更改时返回,即使底层实现错误地解除了阻塞。 我不太明白这两个部分是如何相互关联的。这是否意味着如果值没有更改,那么即使我使用了notify\u one()/方法,函数也不会返回?这意味着该操作在某种程

  • 我正在尝试将数据库调用移出控制器,以清理并使其可测试。当它们在控制器中时,一切都会顺利进行。我将它们移出控制器,并添加了一个异步,以确保我们等待。否则,我将调用的中的函数。现在,一旦我使用async/await,控制器中的函数就会认为没有用户,因为它没有等待。 有几个关于异步等待的SO问题,但我没有找到一个解决我的问题。我确实验证了返回了我的用户,并添加了控制台日志来显示路径。 节点猫鼬异步等待似