您的 loop 功能不循环。它接收第一条消息,触发事件,然后只是...退出。永远不要尝试接收第二条消息。
loop
您需要使该功能连续工作:处理第一条消息,然后返回接收下一条消息,然后接收下一条消息,依此类推。像这样:
let agent = Agent.Start(fun inbox -> let rec loop() = async { let! msg = inbox.Receive() let (Fire i) = msg evt.Trigger i return! loop() } loop())
由于您已达到问题的限制,我将在此处回答您的修改。
您在第二个代码段中获得超时的原因是您的代码中存在死锁。让我们跟踪执行情况以查看它。
collatz
这就是执行结束的地方。代理程序此时无法响应(事实上,它甚至无法接收下一条消息!),因为它的指令指针仍然在里面 evt.Trigger 。该 evt.Trigger 电话还没回来,所以 loop 函数还没有递归,所以 inbox.Receive 函数尚未被调用,因此第二条消息仍在代理队列中等待。
evt.Trigger
inbox.Receive
所以你给自己一个经典的僵局: collatz 正在等待代理接收其消息,但代理正在等待 collatz 完成处理事件。
对此最简单,最愚蠢的解决方案是异步触发事件:
async { evt.Trigger i } |> Async.Start
这将确保事件处理程序不是“正确”执行,而是异步执行,可能在不同的线程上执行。这将允许代理在继续执行自己的执行循环之前不等待事件被处理。
通常,在处理多线程和异步时,不应该直接调用未知代码。代理人永远不应该直接打电话 evt.Trigger 或者其他任何它无法控制的东西,因为代码本身可能正在等待代理本身(这就是你的情况),从而引入了死锁。