Parallel.Invoke不等待异步方法完成
我有一个应用程序从不同的来源提取相当数量的数据。 本地数据库,网络数据库和Web查询。 任何这些都可能需要几秒钟才能完成。 所以,首先我决定并行运行这些:
Parallel.Invoke( () => dataX = loadX(), () => dataY = loadY(), () => dataZ = loadZ() );
正如预期的那样,所有三个并行执行,但是在最后一个块完成之前,整个块上的执行都不会返回。
接下来,我决定在应用程序中添加一个微调器或“忙指示器”。 我不想阻止UI线程或者微调器不会旋转。 所以这些需要在async
模式下运行。 但是如果我在异步模式下运行所有三个,那么它们的影响就会“同步”发生,而不是与UI在同一个线程中。 我仍然希望他们并行运行。
spinner.IsBusy = true; Parallel.Invoke( async () => dataX = await Task.Run(() => { return loadX(); }), async () => dataY = await Task.Run(() => { return loadY(); }), async () => dataZ = await Task.Run(() => { return loadZ(); }) ); spinner.isBusy = false;
现在,Parallel.Invoke不会等待方法完成,并且微调器立即关闭。 更糟糕的是,dataX / Y / Z为空,稍后会发生exception。
这里的正确方法是什么? 我应该使用BackgroundWorker吗? 我希望能够利用.Net 4.5的function。
听起来你真的想要这样的东西:
spinner.IsBusy = true; try { Task t1 = Task.Run(() => dataX = loadX()); Task t2 = Task.Run(() => dataY = loadY()); Task t3 = Task.Run(() => dataZ = loadZ()); await Task.WhenAll(t1, t2, t3); } finally { spinner.IsBusy = false; }
这样你就异步地等待所有任务完成( Task.WhenAll
返回一个任务,当所有其他任务完成时完成),而不阻塞UI线程…而Parallel.Invoke
(和Parallel.ForEach
等)是阻止调用,不应在UI线程中使用。
( Parallel.Invoke
没有阻止您的异步lambdas的原因是它只是等待每个Action
返回…这基本上是在它等待await的开始时。通常你想要分配一个异步lambda到Func
或类似的,就像你不想写async void
方法一样。)
正如您在问题中所述,您的两个方法查询数据库(一个通过sql,另一个通过azure),第三个触发对Web服务的POST请求。 所有这三种方法都在进行I / O绑定工作 。
当您调用Parallel.Invoke
,您基本上会触发三个ThreadPool线程来阻止并等待基于I / O的操作完成,这几乎是浪费资源,并且如果您需要,将会非常严重地扩展。
相反,你可以使用异步apis,它们都暴露出来:
- SQL Server通过Entity Framework 6或ADO.NET
- Azure有异步api
- 通过
HttpClient.PostAsync
发出Web请求
让我们假设以下方法:
LoadXAsync(); LoadYAsync(); LoadZAsync();
你可以像这样打电话给他们:
spinner.IsBusy = true; try { Task t1 = LoadXAsync(); Task t2 = LoadYAsync(); Task t3 = LoadZAsync(); await Task.WhenAll(t1, t2, t3); } finally { spinner.IsBusy = false; }
这将具有相同的期望结果。 它不会冻结您的UI,它可以让您节省宝贵的资源。
- 为什么HashSet 没有实现IReadOnlyCollection ?
- Json.Net无法序列化为流,但可以很好地序列化为字符串
- C#异步等待使用LINQ ForEach()
- 如何使用PasswordBox作为TextBox?
- webbrowser上的c#filenotfoundexception?
- 由json私钥文件(ServiceAccount)创建的GoogleCredential – 如何设置用户模拟?
- 使用out / ref与return相比有什么好处?
- System.IO.FileNotFoundException:在部署应用程序时无法加载文件或程序集“X”或其中一个依赖项
- 异步等待与GetAwaiter()。GetResult()和回调