用户输入超时不能如愿以偿

问题描述 投票:2回答:1

为什么超时后循环周期不能像之前一样工作(不再有打印的用户输入)?

#!/usr/bin/env raku

loop {
    my $str;
    my $timeout = Promise.in( 5 ).then({
        $str = 'Timeout';
    });
    my $user = Promise.start({
        $str = prompt '>';
    });
    await Promise.anyof( $timeout, $user );
    if $str eq 'q' {
        last;
    }
    say "[$str]";
}
asynchronous promise user-input raku
1个回答
6
投票

这是因为你说的是错误的调用 prompt承诺中的,已经关闭了另一个变量的 $str. 第二次和后来的呼吁 prompt 块,等待第一次通话结束。 但是... $str 接收第一次调用的值,但不在范围内,所以什么也没发生。

这听起来很奇怪,但这里有一个实验,你可以运行这个实验来帮助你的直觉,同时我更全面地剖析它:运行脚本,等待超时,然后输入 q 连续两次。 第二遍之后,剧本就退出了。 为什么会这样?

在第一个循环中,我们声明了一个变量 $str 我称之为"$str 1号",并创建一个 Promise 封闭 $str 1号和电话 prompt. prompt 附属于 STDIN 并不返回,直到它看到一个换行。 当超时结束后,对该调用的 prompt 没有被打断。 它还在运行。 还在等待。 它所依附的承诺(我们称它为 $user promise 1)仍然处于活动状态,即使变量的 $user 即将退出范围。

在第二个循环中,我们声明一个新变量 $str ("$str 2号"),创建一个 Promise 封闭 呼叫 prompt 再次。 但另一个电话 prompt 还在使用 STDIN所以新的呼叫会被阻挡并等待 STDIN 以变得可用。 如果你现在键入一些东西,它将被原来的调用看到。prompt隶属于 $user 承诺1和关闭 $str 号码1。

$str 1号在以下情况下更新 prompt 返回,但这并不重要,因为你不再看它。 的 if $str eq 'q' 条件是要检查 $str 2号,因为那是在当前循环中声明的变量。

第二次调用 prompt 然后立即要求输入,如果你输入了 q 在超时之前,它更新了版本的 $str 它关闭过。$str 2号。 因为那是你的条件检查的对象,所以循环终止。

每次超时都会开始一个新的 prompt 而不终止旧的,这意味着用户输入的信息永远不会附加到同一个 $str 的变量。 即使你检查了原始变量,后续的对 prompt 依然会发生,并且在执行离开块后还会不断提示。

由于 prompt 没有办法指定超时,而Raku也没有办法 "杀死 "计划中的 Promises我认为你无法解决这个问题。prompt.


3
投票

在这段代码中,逻辑上的问题是,超时的 Promise 5秒后触发,即使有人在之前的迭代中输入了什么。 所以它会设置 $str 在看似随机的时间。

有一个简单的解决方案:只要确保你做的是 指派 $str 的超时代码中,如果它已经被设置了。

$str //= 'Timeout';

对于这个例子来说,这并不重要, 但一般来说,你不希望代码被随意执行, 所以最好是真正地去激活 Promise. 不幸的是,你不能用 Promise 的接口。 但是 Promise.in 方法实际上是对 ThreadPoolScheduler.cue 方法,它 是否 归还 Cancellation 对象(https:/docs.raku.orgroutinecue。).

© www.soinside.com 2019 - 2024. All rights reserved.