我正在编写一个多人游戏服务器,并且正在寻找新的 C# async/await 功能可以帮助我的方式。服务器的核心是一个循环,它会尽可能快地更新游戏中的所有参与者:
while (!shutdown)
{
foreach (var actor in actors)
actor.Update();
// Send and receive pending network messages
// Various other system maintenance
}
这个循环需要处理数千个actor并每秒更新多次以保持游戏流畅运行。有些演员偶尔会在他们的更新功能中执行缓慢的任务,例如从数据库中获取数据,这是我想使用异步的地方。一旦检索到这些数据,actor 想要更新游戏状态,这必须在主线程上完成。
由于这是一个控制台应用程序,我计划编写一个 SynchronizationContext,它可以将挂起的委托分派到主循环。这允许这些任务在完成后更新游戏,并将未处理的异常抛出到主循环中。我的问题是,如何编写异步更新函数?这非常有效,但违反了不使用 async void 的建议:
Thing foo;
public override void Update()
{
foo.DoThings();
if (someCondition) {
UpdateAsync();
}
}
async void UpdateAsync()
{
// Get data, but let the server continue in the mean time
var newFoo = await GetFooFromDatabase();
// Now back on the main thread, update game state
this.foo = newFoo;
}
我可以使 Update() 异步并将任务传播回主循环,但是:
- 我不想为永远不会使用它的数千个更新增加开销。
- 即使在主循环中,我也不想等待任务并阻塞循环。
- 等待任务无论如何都会导致死锁,因为它需要在等待线程上完成。
我该如何处理所有这些我无法等待的任务?我可能想知道他们都完成的唯一一次是当我关闭服务器时,但我不想收集可能需要数周的更新产生的每一个任务。