C# 立即等待异步任务与先声明然后等待
让我们来看以下两个示例:C# 立即等待异步任务与先声明然后等待,c#,asynchronous,async-await,task,C#,Asynchronous,Async Await,Task,让我们来看以下两个示例: 公共类MyClass { 公共异步任务Main() { var result1=“”; var result2=“”; var request1=await DelayMe(); var request2=await DelayMe(); 结果1=1; 结果2=2; } 专用静态异步任务DelayMe() { 等待任务。延迟(2000); 返回“”; } } 以及: 公共类MyClass { 公共异步任务Main() { var result1=“”; var res
公共类MyClass
{
公共异步任务Main()
{
var result1=“”;
var result2=“”;
var request1=await DelayMe();
var request2=await DelayMe();
结果1=1;
结果2=2;
}
专用静态异步任务DelayMe()
{
等待任务。延迟(2000);
返回“”;
}
}
以及:
公共类MyClass
{
公共异步任务Main()
{
var result1=“”;
var result2=“”;
var request1=DelayMe();
var request2=DelayMe();
结果1=等待请求1;
结果2=等待请求2;
}
专用静态异步任务DelayMe()
{
等待任务。延迟(2000);
返回“”;
}
}
在第一个示例中,显示了通常如何编写async await
代码,其中一件事情发生在另一件事情之后,并被正确地等待
第二个是首先调用async Task
方法,但它正在等待
稍后调用它
第一个示例需要超过4000ms
一点的时间来执行,因为wait
在发出第二个请求之前正在计算第一个请求;但第二个示例的时间略大于2000ms
。之所以会出现这种情况,是因为只要执行步骤跨过var request1=DelayMe(),任务实际上就会开始运行代码>行,表示request1
和request2
并行运行。此时,await
关键字似乎只是确保计算了任务
第二种方法的感觉和行为类似于等待任务。当所有(request1,request2)
,但在这种情况下,如果两个请求中出现故障,您将立即获得异常,而不是等待所有内容计算,然后获得一个聚合异常
我的问题是,当一个任务的结果不依赖于另一个任务的执行时,使用第二种方法并行运行多个await
ableTask
s是否存在缺陷(性能或其他方面)?查看降低的代码,第二个示例似乎为每个等待的项生成等量的System.Threading.Tasks.Task
1,而第一个示例则没有。这是否仍在进行异步等待`状态机流?使用第二种方法并行运行多个等待任务的缺点是并行性不明显。而不明显的并行性(换句话说,隐式多线程)是危险的,因为可能引入的bug是众所周知的不一致的,并且偶尔会被观察到。让我们假设在生产环境中运行的实际DelayMe
如下所示:
private static int delaysCount = 0;
private static async Task<String> DelayMe()
{
await Task.Delay(2000);
return (++delaysCount).ToString();
}
private static int delayscont=0;
专用静态异步任务DelayMe()
{
等待任务。延迟(2000);
return(++delayScont).ToString();
}
按顺序等待的对DelayMe
的调用将返回递增的数字。并行等待的呼叫偶尔会返回相同的号码
如果在这两个请求中出现故障,您将立即得到一个异常,而不是等待所有内容都计算,然后得到一个AggregateException
如果第一次请求失败,那么是。如果第二个请求失败,则为否,在该任务wait
ed之前,您不会检查第二个请求的结果
我的问题是,当一个任务的结果不依赖于另一个任务的执行时,使用第二种方法并行运行多个等待的任务是否有缺点(性能或其他方面)?查看降低的代码,第二个示例生成的System.Threading.Tasks.Task1per waitied item数量与第一个示例相同,而第一个示例没有生成。这是否仍在通过同步等待状态机流
它仍在通过状态机流程。我倾向于推荐wait Task.whalll
,因为代码的意图更加明确,但有些人不喜欢“即使有异常也要等待”的行为。另一方面是任务。当所有的总是收集所有异常时-如果您有快速失败行为,那么一些异常可以忽略
关于性能,并发执行会更好,因为您可以同时执行多个操作。由于async
/await
不使用额外的线程,因此不会出现线程池耗尽的危险
作为补充说明,我建议使用术语“异步并发”而不是“并行”,因为对许多人来说,“并行”意味着并行处理,即,并行
或PLINQ,在这种情况下使用这种技术是错误的。我看不出任何缺点,但如果我是为非依赖性任务这样做的,我会使用Task.WhenAll()
。在某些情况下,您可能只想完成其中一项任务(其中一项可能是超时),在这种情况下,您可以使用Task.whenny()
。我怀疑这个问题背后的实际问题是完全不同的。这两种等待的明显问题是,您可能必须等待最慢的任务完成,然后才能获得任何异常—任何提前完成的任务。如果你关心这些事情,尽管你不应该这样写任务。早期中止可以通过使用CancellationTokenSource来完成,例如,如果任何异步操作决定中止,将发出信号。如果您需要调用eg 3不同的服务获取数据,而不是在顶层等待任何故障,您可以将CancellationToken传递给工作函数,如果其中任何一个函数捕捉到异常,将发出通知。Th