Правя сървъра на мултиплеър игра и опитвам да разбера как да използвам функциите на async/await. Ядрото на сървъра е цикъл, който обновява участниците в играта колкото може по-бързо
while (!shutdown)
{
foreach (var actor in actors)
actor.Update();
}
Цикълът трябва да обработва хиляди участници много пъти в секунда, за да върви играта гладко. Някои участници обаче изпълняват бавни задачи в тяхното обновяване, като взимане на дании от базата, което искам да става асинхронно. След като се вземат тези данни, участникът трябва да се обнови, което става в основната нишка.
Тъй като е конзолно приложение, искам да напиша SynchronizationContext, който да изпраща делегати в основния цикъл. Това ще позволи на задачите да обновяват играта веднага щом завършат и необработени изключения ще се хвърлят в основния цикъл. Въпросът ми е, как да напиша асинхронно функциите за обновяване? Това работи добре, но не спазва препоръката да не се използва async void:
Thing foo;
public override void Update()
{
foo.DoThings();
if (someCondition) {
UpdateAsync();
}
}
async void UpdateAsync()
{
// взима данни, но сървъра си продължава през това време
var newFoo = await GetFooFromDatabase();
// в основната нишка обновява състоянието на играта
this.foo = newFoo;
}
Мога да направя Update() с async и да пращам задачите в основия цикъл, но:
- Не искам да натоварвам хилядите обновления,които няма да го използват
- Дори в основния цикъл не искам да await-вам тези задачи и това ще блокира цикъла
- Изчакването на задачата ще причини deadlock, тъй като трябва да се завърши на изчакващата нишка
Какво да правя със задачите, които не мога да await-на? Единствено когато изключвам сървъра ще искам да знам, че всички са завършили, но не искам да съхранявам всяка една задача, която се генерира.