Я пишу многопользовательский игровой сервер и ищу способы, которыми новые функции C # async / await могут мне помочь. Ядро сервера - это цикл, который максимально быстро обновляет всех действующих лиц в игре:
while (!shutdown)
{
foreach (var actor in actors)
actor.Update();
// Send and receive pending network messages
// Various other system maintenance
}
Этот цикл необходим для обработки тысяч актеров и обновления несколько раз в секунду, чтобы игра работала плавно. Некоторые субъекты иногда выполняют медленные задачи в своих функциях обновления, такие как выборка данных из базы данных, где я бы хотел использовать async. После получения этих данных актер хочет обновить состояние игры, что должно быть выполнено в основном потоке.
Поскольку это консольное приложение, я планирую написать 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 () асинхронным и передать задачи обратно в основной цикл, но:
- Я не хочу увеличивать накладные расходы на тысячи обновлений, которые никогда не будут использовать его.
- Даже в основном цикле я не хочу ждать задач и блокировать цикл.
- Ожидание задачи в любом случае приведет к тупиковой ситуации, поскольку она должна завершиться в ожидающем потоке.
Что мне делать со всеми этими задачами, которых я не могу дождаться? Единственный раз, когда я могу захотеть узнать, что все они закончили, - это когда я выключаю сервер, но я не хочу собирать каждую задачу, созданную потенциально неделями обновлений.
Parallel.ForEach
на обычныйforeach
, если хотите, чтобы они также выполнялись последовательно, но вы в значительной степени потеряете преимущества многоядерной архитектуры ЦП. - person noseratio   schedule 11.09.2013