在没有明确检查的情况下取消等待任务

时间:2014-02-20 15:40:01

标签: c# .net asynchronous async-await

我正在开发一款使用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是否在某个地方关闭了。但是我希望它们尽可能简单直接,坦率地说,每次调用一个函数后,如果我的口味太过乏味,那么它就会变得过于乏味。新手也会使用服务器软件,他们可能会忘记这样的检查,这可能会导致问题,具体取决于脚本的功能。

我现在的实际问题是,如果有人能够想出取消任务的方法,而无需对脚本本身进行明确检查。

3 个答案:

答案 0 :(得分:3)

TPL具有内置的取消功能。

让所有函数接受CanellationToken,并在调用每个异步函数时传递令牌。

在函数内部,不时地调用token.ThrowIfCancellationRequested(),整个异步调用链将中止,直到您处理取消。

答案 1 :(得分:1)

您可以安装可以取消的自定义SynchronizationContext。取消时它就会停止调用延续。 async方法会在下一个await之后立即停止。如果没有任何东西可以保留这些任务,那么他们就会被GC控制,然后就会消失。

请注意,即使finally块也不会执行此方式。 using不会进行清理等。在这种情况下,您的代码必须经过强化才能保证安全。

答案 2 :(得分:0)

这是一个简短的答案。

如果您想安全中止,任务取消必须始终是合作取消。