我正在开发一款使用C#作为其NPC脚本的在线游戏服务器。为了获得无状态NPC,我正在使用枚举器,当我必须等待来自客户端的响应时产生,并在我得到它后调用MoveNext。
Talk()
Msg("test");
Select("Yes", "No");
yield return true;
Msg(Response);
(简化示例,实际上屈服更复杂。)
这样可以正常工作,但异步/等待可以使其更清晰,更简单,更灵活。
Talk()
Msg("test");
Msg(await Select("Yes", "No"));
玩异步/等待我发现我唯一的问题是脚本不像发送一些消息那么简单。当从主Talk函数调用其他函数时,我必须等待它们,因为否则执行不会停止。其他功能也可以调用更多,创建未知数量的等待。
Talk()
Msg("test");
await OtherTalk();
Msg("end"); // would be called right away
OtherTalk()
Msg("test2");
Msg(await Select("Yes", "No"));
如果我在这种“次要谈话”方法中关闭NPC,我可能会在空中留下相当多的任务,因为我不会回到连锁店。全国人大关闭,没有更多的回应,任务一直在等待。
这个问题的解决方案是将链条备份,在等待这样一个函数之后进行显式检查,以检查NPC是否在某个地方关闭了。但是我希望它们尽可能简单直接,坦率地说,每次调用一个函数后,如果我的口味太过乏味,那么它就会变得过于乏味。新手也会使用服务器软件,他们可能会忘记这样的检查,这可能会导致问题,具体取决于脚本的功能。
我现在的实际问题是,如果有人能够想出取消任务的方法,而无需对脚本本身进行明确检查。
答案 0 :(得分:3)
TPL具有内置的取消功能。
让所有函数接受CanellationToken
,并在调用每个异步函数时传递令牌。
在函数内部,不时地调用token.ThrowIfCancellationRequested()
,整个异步调用链将中止,直到您处理取消。
答案 1 :(得分:1)
您可以安装可以取消的自定义SynchronizationContext
。取消时它就会停止调用延续。 async
方法会在下一个await
之后立即停止。如果没有任何东西可以保留这些任务,那么他们就会被GC控制,然后就会消失。
请注意,即使finally
块也不会执行此方式。 using
不会进行清理等。在这种情况下,您的代码必须经过强化才能保证安全。
答案 2 :(得分:0)
这是一个简短的答案。
如果您想安全中止,任务取消必须始终是合作取消。