为什么超时后循环周期不能像之前一样工作(不再有打印的用户输入)?
#!/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]";
}
这是因为你说的是错误的调用 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
.
在这段代码中,逻辑上的问题是,超时的 Promise 会 5秒后触发,即使有人在之前的迭代中输入了什么。 所以它会设置 $str
在看似随机的时间。
有一个简单的解决方案:只要确保你做的是 不 指派 $str
的超时代码中,如果它已经被设置了。
$str //= 'Timeout';
对于这个例子来说,这并不重要, 但一般来说,你不希望代码被随意执行, 所以最好是真正地去激活 Promise
. 不幸的是,你不能用 Promise
的接口。 但是 Promise.in
方法实际上是对 ThreadPoolScheduler.cue
方法,它 是否 归还 Cancellation
对象(https:/docs.raku.orgroutinecue。).