基于Raku并发实现可停止简易定时器的技术咨询
如何在Raku中实现可停止的定时器?
你的原始代码核心问题在于:start方法里的无限循环直接阻塞了主线程,导致后续的stop和reset调用根本没机会执行,而且Promise也没真正发挥并发控制的作用。下面给出两种基于Raku并发特性的实现方案,彻底解决这个问题:
方案一:用Promise实现可停止定时器
这种方式通过后台线程执行定时器循环,用Promise作为停止信号,逻辑清晰且灵活:
class Timer { has Promise $!stop-promise; has Promise $!timer-promise; has Int $!counter is default(0); has Bool $!is-running is default(False); method start { return if $!is-running; # 避免重复启动 $!is-running = True; $!stop-promise = Promise.new; # 用start块把循环放到后台线程,不阻塞主线程 $!timer-promise = start { loop { # 同时等待1秒定时或停止信号,哪个先触发就执行哪个 await Promise.anyof($!stop-promise, Promise.in(1)); # 如果停止信号被触发,直接退出循环 last if $!stop-promise.Broken; $!counter++; self.show; } $!is-running = False; } } method stop { return unless $!is-running; # 触发停止信号(若未触发过) $!stop-promise.break unless $!stop-promise.Broken; # 可选:等待后台线程完全结束,确保资源清理 await $!timer-promise; } method reset { $!counter = 0; self.show; } method show { say "timer: $!counter"; } } # 使用示例 my Timer $t .= new; $t.start; sleep 3; # 让定时器运行3秒 $t.stop; $t.reset;
关键改动说明:
- 用
start关键字将定时器循环放到后台线程执行,主线程得以释放,能正常处理stop和reset调用。 - 新增
$!stop-promise作为停止信号,stop方法通过break触发该Promise,循环中通过Promise.anyof监听停止信号和1秒定时,收到停止信号就退出循环。 - 加入
$!is-running标志,防止重复启动定时器。
方案二:用Supply实现可停止定时器
Raku的Supply天生适合处理周期性事件,这种方式代码更简洁:
class Timer { has Supply $!timer-supply; has Supplier $!control-supplier; has Int $!counter is default(0); has Bool $!is-running is default(False); method start { return if $!is-running; $!is-running = True; # 创建控制信号源,用于发送停止指令 $!control-supplier = Supplier.new; my $control-supply = $!control-supplier.Supply; # 创建每秒触发一次的事件流 $!timer-supply = Supply.interval(1) .tap( # 每次触发时计数并显示 -> $ { $!counter++; self.show; }, # 事件流关闭时标记定时器停止 done => { $!is-running = False } ); # 监听控制信号,收到后关闭定时器事件流 $control-supply.tap: -> $ { $!timer-supply.close } } method stop { return unless $!is-running; # 发送停止信号 $!control-supplier.emit('stop'); } method reset { $!counter = 0; self.show; } method show { say "timer: $!counter"; } } # 使用示例 my Timer $t .= new; $t.start; sleep 3; $t.stop; $t.reset;
关键改动说明:
- 用
Supply.interval(1)生成每秒触发一次的事件流,通过tap处理计数和显示逻辑。 - 创建
control-supplier生成控制信号,stop方法通过emit发送停止信号,监听该信号的tap会关闭定时器Supply,终止事件流。
内容的提问来源于stack exchange,提问作者librasteve
相关产品推荐
相关产品推荐

