Monday, 9 September 2013

What do I do with async Tasks I don't want to wait for?

What do I do with async Tasks I don't want to wait for?

I am writing a multi player game server and am looking at ways the new C#
async/await features can help me. The core of the server is a loop which
updates all the actors in the game as fast as it can:
while (!shutdown)
{
foreach (var actor in actors)
actor.Update();
// Send and receive pending network messages
// Various other system maintenance
}
This loop is required to handle thousands of actors and update multiple
times per second to keep the game running smoothly. Some actors
occasionally perform slow tasks in their update functions, such as
fetching data from a database, which is where I'd like to use async. Once
this data is retrieved the actor wants to update the game state, which
must be done on the main thread.
As this is a console application, I plan to write a SynchronizationContext
which can dispatch pending delegates to the main loop. This allows those
tasks to update the game once they complete and lets unhandled exceptions
be thrown into the main loop. My question is, how do write the async
update functions? This works very nicely, but breaks the recommendations
not to use 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;
}
I could make Update() async and propogate the tasks back to the main loop,
but:
I don't want to add overhead to the thousands of updates that will never
use it.
Even in the main loop I don't want to await the tasks and block the loop.
Awaiting the task would cause a deadlock anyway as it needs to complete on
the awaiting thread.
What do I do with all these tasks I can't await? The only time I might
want to know they've all finished is when I'm shutting the server down,
but I don't want to collect every task generated by potentially weeks
worth of updates.

No comments:

Post a Comment