c# – 我如何处理异步任务我不想等待?

前端之家收集整理的这篇文章主要介绍了c# – 我如何处理异步任务我不想等待?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在写一个多玩家游戏服务器,并正在寻找新的C#异步/等待功能方法
帮我.服务器的核心是更新游戏中所有角色的循环
能够:
while (!shutdown)
{
    foreach (var actor in actors)
        actor.Update();

    // Send and receive pending network messages
    // VarIoUs other system maintenance
}

需要这个循环来处理数千个演员,并且每秒钟更新多次以保持
游戏运行顺利.有些演员偶尔会在其更新功能中执行较慢的任务,例如
数据库获取数据,这是我要使用异步的地方.一旦检索到这个数据
演员想要更新游戏状态,这必须在主线程上完成.

由于这是一个控制台应用程序,我打算写一个可以发送的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()异步并将任务传播回主循环,但是:

>我不想增加数千个永远不会使用它的更新的开销.
>即使在主循环中,我也不想等待任务并阻止循环.
>等待任务会导致死锁,因为它需要在等待线程上完成.

我不能等待的所有这些任务怎么办?唯一的时候,我可能想知道他们所有
完成是当我关闭服务器下来,但我不想收集每个生成的任务
潜在的星期值得更新.

解决方法

我的理解是,它的关键是你想要的:
while (!shutdown)
{
    //This should happen immediately and completions occur on the main thread.
    foreach (var actor in actors)
        actor.Update(); //includes i/o bound database operations

    // The subsequent code should not be delayed
   ...
}

while循环在主控制台线程中运行的位置.这是一个紧密的单线程循环.您可以并行运行foreach,但是您仍然会等待最长的运行实例(i / o绑定操作从数据库获取数据).

等待异步不是此循环中的最佳选项,您需要在线程池上运行这些i / o数据库任务.在线程池异步等待将释放池线程是有用的.

所以,下一个问题是如何将这些完成回到主线程.嗯,好像你需要一些相当于主线程上的消息泵的东西.有关如何做到这一点的信息,请参阅this post,尽管这可能有点沉重.您可以在每次通过while循环时,在主线程上检查完成队列.您将使用concurrent data structures之一来做到这一点,所有这些都是线程安全的,然后设置Foo如果需要设置.

似乎有一些空间来合理化这个投票的演员和线程,但是不知道应用程序的细节是很难说的.

几点: –

>如果您没有等待更高的任务,您的主控制台线程将退出,您的应用程序也将退出.详见here.
>正如你所指出的那样,等待异步不阻止当前线程,但这意味着等待之后的代码只能在完成等待时执行.
>完成可能也可能不会在调用线程上完成.您已经提到了同步上下文,所以我不会详细介绍.
>同步上下文在控制台应用程序为空.参见here获取信息.
>异步不是真正的火和忘记类型的操作.

对于火而忘记,您可以根据您的方案使用以下选项之一:

>使用Task.Run或Task.StartNew.见here for differences.
>为您自己的线程池运行的长时间运行的方案使用生产者/消费者类型模式.

请注意以下事项: –

>您将需要处理您生成的任务/线程中的异常.如果您没有观察到任何异常,您可能需要处理这些异常,即使只是记录其发生.请参阅unobserved exceptions上的信息.
>如果您的进程在这些长时间运行的任务在队列中或者开始时不会运行,那么您可能需要某种持久化机制(数据库,外部队列,文件)来跟踪这些操作的状态.

如果您想了解这些任务的状态,那么您将需要以某种方式跟踪它们,无论是内存列表还是通过查询自己的线程池的队列或通过查询持久性机制进行查询.关于持久性机制的好处是,它对崩溃是有弹性的,在关机期间,您可以立即关闭,然后在重新启动的时候选择你最后的位置(这当然取决于任务运行的重要程度一段时间内).

原文链接:https://www.f2er.com/csharp/95873.html

猜你在找的C#相关文章