Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/261.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 不必要的异步/等待何时是最后一次?_C#_.net_Task Parallel Library_Async Await_C# 5.0 - Fatal编程技术网

C# 不必要的异步/等待何时是最后一次?

C# 不必要的异步/等待何时是最后一次?,c#,.net,task-parallel-library,async-await,c#-5.0,C#,.net,Task Parallel Library,Async Await,C# 5.0,我最近一直在处理很多关于async Wait的问题(阅读所有可能的文章,包括Stephen和Jon的最后两章),但我已经得出结论,我不知道它是否100%正确。-这就是我的问题 由于async只允许单词wait出现,因此我将async放在一边 阿法尤,等待就是继续。编写同步代码,而不是编写函数(连续)代码。(我喜欢将其称为可回调代码) 因此,当编译器到达await-它将代码分成两部分,并在第一部分完成后注册第二部分执行(我不知道为什么没有使用回调这个词,这正是所做的)。(同时工作-线程正在返回执行

我最近一直在处理很多关于async Wait的问题(阅读所有可能的文章,包括Stephen和Jon的最后两章),但我已经得出结论,我不知道它是否100%正确。-这就是我的问题

由于
async
只允许单词wait出现,因此我将
async
放在一边

阿法尤,等待就是继续。编写同步代码,而不是编写函数(连续)代码。(我喜欢将其称为可回调代码)

因此,当编译器到达
await
-它将代码分成两部分,并在第一部分完成后注册第二部分执行(我不知道为什么没有使用
回调
这个词,这正是所做的)。(同时工作-线程正在返回执行其他操作)

但是看看这个代码:

public async  Task ProcessAsync()
        {
           Task<string> workTask = SimulateWork();
           string st= await workTask;
           //do something with st
        }

 public    Task <string> SimulateWork()
        {
            return ...
        }
这里-我不需要继续,意思是-我不需要
await
来分割方法,这意味着-我根本不需要async/await而且我仍然会有相同的结果/行为

所以我可以这样做:

   public void ProcessAsync()
            {
               SimulateWork();
            }
问题:

  • 我的诊断是否100%正确
      你很接近了。这意味着你可以这样写:

      public Task ProcessAsync()
      {
          // some sync code
          return SimulateWork();
      }
      

      这样,您就不必“支付”将方法标记为
      async
      的开销,但您仍然能够等待整个操作。

      因此,您认为下面的
      wait
      是多余的,正如问题的标题所示:

      公共异步任务ProcessAsync()
      {
      任务=模拟工作();
      wait workTask;//我不在乎结果,也没有进一步的问题
      }
      
      首先,我假设在“when
      await
      是最后一个”下,您的意思是,when
      await
      是唯一的
      await
      。必须是这样的,否则以下内容将无法编译:

      公共异步任务ProcessAsync()
      {
      等待任务。延迟(1000);
      任务=模拟工作();
      返回工作任务;
      }
      
      现在,如果它是唯一的
      等待
      ,您确实可以这样优化它:

      public Task ProcessAsync()
      {
          // some sync code
          return SimulateWork();
      }
      
      public Task ProcessAsync()
      {
      任务=模拟工作();
      返回工作任务;
      }
      
      但是,它会给您带来完全不同的异常传播行为,这可能会产生一些意想不到的副作用。问题是,根据
      SimulateWork
      的内部实现方式,现在可能会在调用方的堆栈上抛出异常。我贴了一封信。这通常不会发生在
      async
      Task
      /
      Task
      方法中,其中异常存储在返回的
      Task
      对象中。对于
      异步void
      方法,仍然可能发生这种情况,但这是一种错误

      因此,如果您的调用方代码已准备好处理异常传播中的此类差异,最好尽可能跳过
      async/await
      ,而只返回
      任务

      另一个问题是,如果你想发出一个火灾和遗忘电话。通常,您仍然希望以某种方式跟踪已启动任务的状态,至少出于处理任务异常的原因。我无法想象有一种情况,我真的不在乎任务是否从未完成,即使它所做的只是记录日志

      因此,对于fire and forget,我通常使用helper
      async void
      方法,将挂起的任务存储在某个地方供以后观察,例如:

      readonly对象_syncLock=new object();
      只读哈希集_pendingTasks=新哈希集();
      异步无效队列任务异步(任务任务)
      {
      //将失败/取消的任务保留在列表中
      //他们将在外面被观察
      锁(同步锁)
      _添加(任务);
      尝试
      {
      等待任务;
      }
      抓住
      {
      //这不是task的例外吗?
      如果(!task.iscancelled&&!task.IsFaulted)
      抛出;//重新抛出
      //吞咽,但不要从_pendingTasks中删除出现故障/已取消的任务
      //稍后,当我们处理挂起的任务时,将观察到错误,
      //例如:wait Task.WhenAll(_pendingTasks.ToArray())
      返回;
      }
      //从列表中删除成功完成的任务
      锁(同步锁)
      _pendingTasks.Remove(任务);
      }
      
      你可以这样称呼它:

      public Task ProcessAsync()
      {
          // some sync code
          return SimulateWork();
      }
      
      public Task ProcessAsync()
      {
      QueueTaskAsync(SimulateWork());
      }
      
      目标是在当前线程的同步上下文上立即抛出致命异常(例如,内存不足),而任务结果/错误处理将延迟到适当的时间


      有一个有趣的讨论是使用fire and forget任务。

      要100%纯重写,您仍然应该返回
      任务
      ,而不是
      无效
      ,并且应该返回
      模拟工作
      返回的
      任务
      -这样,
      ProcessAsync
      的调用方仍然可以
      等待
      (或
      等待
      )在这个
      任务上
      要知道你什么时候完成了。你应该始终关心任务是如何完成的。@PauloMorgado我不同意这个说法。在我的示例中,只有当我需要知道
      ProcessAsync
      发生了什么时,它才是相关的。在某些情况下,fire和forget是合法的。如果任务以错误结束,会发生什么?Jus我不喜欢在后台线程执行时处理线程内部的错误.如果延续如此重要,而A依赖于B,那么就像我说的,使用wait/continuewith@RoyiNamir如果您指的是
      async void
      事件处理程序,那么它们必须保持
      async
      以支持异步操作,这与
      ProcessAsync
      不同,后者很容易被标记为
      async
      ,而没有真正的更改任何内容。是的,我知道,jsut提到他们将无法使用任务返回类型。需要了解的重要部分是,您的void retu