用coroutines / C#5实现无状态NPC脚本等待

时间:2011-12-29 16:28:18

标签: c# scripting async-await c#-5.0

我正在尝试使用C#的新await功能实现NPC脚本。 This is my proof of concept.

NPC.cs中,您可以看到以下代码段:

public async void Run(INPC npc)
{
    npc.Say("Hello!");
    await npc.WaitForOk();
    npc.Say("This is an example of some weird crap.");
    await npc.WaitForOk();
    npc.Say("Bye.");
    await npc.WaitForOk();
}

在一个真实的例子中,脚本将以IronPython等脚本语言实现。即使它将来可能支持async / await关键字,但每次通话都必须这样做是非常麻烦和恼人的。

我尝试过另一种方法是异步并进行等待,让脚本只是调用它,但由于async / await的工作方式,脚本方法({{1只会继续而不会暂停/阻止。

有没有办法避免必须使脚本方法异步并且必须在每次调用前使用Run,同时仍然保留类似协程的功能?

此外,如果有一个更好的解决方案已经可用,而不是使用await / async同时仍然保持线程效率,请突出显示它。

谢谢!

2 个答案:

答案 0 :(得分:1)

对于async / await来说,这是一个非常有趣的用途。

我已经将很多与语法相关的问题从网络编译成one of my blog posts。简而言之,有充分理由说明asyncawait都是必需的。

如果您愿意向NPC添加状态,请考虑使用基于观察者的方法(Rx)。这种方法能够进行复杂的交互,也可以允许并行执行不同的NPC。

您还可以在线程池任务上模拟NPC,这非常有效 - 当它们阻塞时,CPU可用于其他任务。

答案 1 :(得分:1)

我不确定你为什么要这么努力避免await。我认为对这种代码要求它是一个好主意,因为很难说出代码实际上做了什么。所以,我认为以这种方式使用await可能是你最好的选择。

另外,如果可以的话,最好避免使用async void方法,因为你无法捕获它们抛出的异常。

我可以想象有办法避免写async,例如:

npc.AddAction(n => n.Say("Hello!"))
   .AddAction(n => n.WaitForOk())
   .AddAction(n => n.Say("This is an example of some weird crap."))
   .AddAction(n => n.WaitForOk());

npc.Run();

此处,Run()处理使用AddAction()构建的操作列表,并在必要时使用await

但我怀疑你能否像使用await s那样简单。 (另外,在这样的代码中实现任何类型的控制流都会使它真的难以理解。)