【问题标题】:Is it possible to terminate a promise's code block from another promise?是否可以从另一个 Promise 中终止 Promise 的代码块?
【发布时间】:2018-10-23 18:44:45
【问题描述】:

我写了这个测试程序:

await Promise.anyof(
  Promise.allof((^5).map: {start { sleep 10; say "done $_" } }),
  Promise.in(5).then: { say 'ouch' }
);
sleep 10;

当第二个 promise 超时时,它会打印 'ouch' 并且 await 退出,但第一个 promise 的代码块仍在运行。再过五秒钟,它的五个进程结束并打印“完成”:

$ ./test1.p6
ouch
done 0
done 1
done 2
done 3
done 4

我试图终止第一个 Promise 并将其分配给一个变量,然后从第二个 Promise 调用 .break 方法,但它不起作用。

有没有办法杀死第一个 Promise 和它启动的其他五个子 Promise?

【问题讨论】:

    标签: concurrency promise raku


    【解决方案1】:

    你必须以某种方式告诉进程它不必完成。

    my $cancel = Cancellation.new;
    
    await Promise.anyof(
      Promise.allof(
        (^5).map: {
          last if $cancel.cancelled;
    
          start {
            sleep 10;
            say "done $_" unless $cancel.cancelled
          }
        }
      ),
      Promise.in(5).then: {
        $cancel.cancel;
        say 'ouch'
      }
    );
    

    如果您想要像Promise.in() 这样可以取消的东西,让我们从looking at the existing code 开始。

    method in(Promise:U: $seconds, :$scheduler = $*SCHEDULER) {
        my $p   := self.new(:$scheduler);
        my $vow := $p.vow;
        $scheduler.cue({ $vow.keep(True) }, :in($seconds));
        $p
    }
    

    注意$scheduler.cue 的结果是取消。

    为了简单起见,我只是将 Promise 和 Cancellation 包装在一个类中。
    (我不想重新实现每个方法)。

    class Cancellable-Timer {
        has Promise      $.Promise;
        has              $!vow;
        has Cancellation $!cancel;
    
        method !SET-SELF ( $!promise, $!vow, $!cancel ){
            self
        }
    
        method in (::?CLASS:U: $seconds, :$scheduler = $*SCHEDULER) {
            my $p   := Promise.new(:$scheduler);
            my $vow := $p.vow;
            my $cancel = $scheduler.cue({ $vow.keep(True) }, :in($seconds));
            self.bless!SET-SELF($p,$vow,$cancel);
        }
    
        method cancel ( --> Nil ) {
            # potential concurrency problem
            if $!Promise.status == Planned {
                $!cancel.cancel;          # cancel the timer
                $!vow.break("cancelled"); # break the Promise
            }
        }
    
        method cancelled () {
            # Ignore any concurrency problems by using the Promise
            # as the sole source of truth.
            $!Promise.status ~~ PromiseStatus::Broken
        }
    }
    
    my $timer = Cancellable-Timer.in(1);
    my $say = $timer.Promise.then: *.say;
    Promise.in(0.1).then: {$timer.cancel};
    await $say;
    

    请注意,上面的课程只是一个粗略的初稿。

    【讨论】:

    • 有办法取消 Promise.in() 吗? (将Promise.in(5)改成Promise.in(15)表示退出await后继续执行;可以写say 'ouch' unless $cancel.cancelled但超时过程仍然运行)
    • @FernandoSantagata Promise.in 只是 $scheduler.cue({ $vow.keep(True) }, :in($seconds))
    • @FernandoSantagata 我刚刚添加了可以做到这一点的代码。
    【解决方案2】:

    随时尝试

    $ perl6 -e '
    
    react {
       for ^5 -> $num {
          whenever start { sleep 10 } {
             say "done $num"
          }
       }
       whenever Promise.in: 5 {
          say "ouch";
          done
       }
    }
    
    ' ouch
    

    【讨论】:

    • 一开始我实际上尝试使用一个react block,但是程序稍微复杂一些,react block 不起作用。由于无法在注释中添加格式化代码,因此这里有一个 pastebin:pastebin.com/wzxscNWx 当您留下注释的那部分代码时,它会按预期工作,但是如果将其删除,奇怪的是代码会运行整个 10 秒间隔;我无法解释为什么。
    猜你喜欢
    • 2017-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-29
    • 2023-03-31
    • 2021-03-03
    • 2017-07-31
    相关资源
    最近更新 更多