C#链接ContinueWith不等待上一个任务完成

编程入门 行业动态 更新时间:2024-10-24 20:15:05
本文介绍了C#链接ContinueWith不等待上一个任务完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我正在测试C#async/await的异步性,并遇到一个意外的情况,ContinueWith的后续代码不等待上一个任务完成:

I am testing the asynchronousity of C# async/await and came across a surprise where the subsequent code for ContinueWith does not wait for the previous task to complete:

public async Task<int> SampleAsyncMethodAsync(int number,string id) { Console.WriteLine($"Started work for {id}.{number}"); ConcurrentBag<int> abc = new ConcurrentBag<int>(); await Task.Run(() => { for (int count = 0; count < 30; count++) { Console.WriteLine($"[{id}] Run: {number}"); abc.Add(count); } }); Console.WriteLine($"Completed work for {id}.{number}"); return abc.Sum(); }

使用以下测试方法执行

[Test] public void TestAsyncWaitForPreviousTask() { for (int count = 0; count < 3; count++) { int scopeCount = count; var c = SampleAsyncMethodAsync(0, scopeCount.ToString()) .ContinueWith((prevTask) => { return SampleAsyncMethodAsync(1, scopeCount.ToString()); }) .ContinueWith((prevTask2) => { return SampleAsyncMethodAsync(2, scopeCount.ToString()); }); } }

输出显示运行0.0、1.0和2.0的执行正确异步执行,但随后的x.1和x.2几乎立即启动,而x.2实际上在x.1之前完成.例如.如下所示:

The output shows execution for runs 0.0,1.0 and 2.0 executes asynchronously correctly but subsequent x.1 and x.2 get started almost immediately and x.2 actually completes before x.1. E.g. as logged below:

[2] Run: 0 [2] Run: 0 [2] Run: 0 Completed work for 2.0 Started work for 0.1 Started work for 0.2 <-- surprise! [0] Run: 2 [0] Run: 2 [0] Run: 2 [0] Run: 2 [0] Run: 2

似乎continuWith只会等待第一个任务(0),而与后续链无关.我可以通过将第二个ContinueWith嵌套在第一个Continuewith块中来解决问题.

It seems the continueWith will only wait on the first task (0) regardless of subsequent chains. I can solve the problem by nesting the second ContinueWith within the first Continuewith block.

我的代码有问题吗?我假设Console.WriteLine尊重FIFO.

Is there something wrong with my code? I'm assuming Console.WriteLine respects FIFO.

推荐答案

简而言之,您希望 ContinueWith 等待先前返回的对象.在 ContinueWith 操作中返回对象(甚至是 Task )对返回值不执行任何操作,它不等待其完成,而是将其返回并传递到延续(如果存在)

In short, you expect ContinueWith to wait for a previously returned object. Returning an object (even a Task) in ContinueWith action does nothing with returned value, it does not wait for it to complete, it returns it and passes to the continuation if exists.

确实发生了以下事情:

  • 您运行 SampleAsyncMethodAsync(0,scopeCount.ToString())
  • 完成后,执行延续1:

  • You run SampleAsyncMethodAsync(0, scopeCount.ToString())
  • When it is completed, you execute the continuation 1:

return SampleAsyncMethodAsync(1, scopeCount.ToString());

,当偶然发现 await Task.Run 时,它将返回一个任务.即,它不等待SampleAsyncMethodAsync完成.

and when it stumbles upon await Task.Run, it returns a task. I.e., it does not wait for SampleAsyncMethodAsync to complete.

如果您手动等待每个异步方法,那么它将随之运行:

If you wait for every asynchronous method manually, then it will run consequently:

for (int count = 0; count < 3; count++) { int scopeCount = count; var c = SampleAsyncMethodAsync(0, scopeCount.ToString()) .ContinueWith((prevTask) => { SampleAsyncMethodAsync(1, scopeCount.ToString()).Wait(); }) .ContinueWith((prevTask2) => { SampleAsyncMethodAsync(2, scopeCount.ToString()).Wait(); }); }

使用 ContinueWith(async t =>等待SampleAsyncMethodAsync ... 也不能正常工作,因为它会导致包装的 Task< Task> 结果(解释清楚)此处).

Using ContinueWith(async t => await SampleAsyncMethodAsync... doesn't work as well, since it results into wrapped Task<Task> result (explained well here).

此外,您可以执行以下操作:

Also, you can do something like:

for (int count = 0; count < 3; count++) { int scopeCount = count; var c = SampleAsyncMethodAsync(0, scopeCount.ToString()) .ContinueWith((prevTask) => { SampleAsyncMethodAsync(1, scopeCount.ToString()) .ContinueWith((prevTask2) => { SampleAsyncMethodAsync(2, scopeCount.ToString()); }); }); }

但是,它创建了某种回调地狱,看起来很凌乱.

However, it creates some sort of callback hell and looks messy.

您可以使用 await 使此代码更简洁:

You can use await to make this code a little cleaner:

for (int count = 0; count < 3; count++) { int scopeCount = count; var d = Task.Run(async () => { await SampleAsyncMethodAsync(0, scopeCount.ToString()); await SampleAsyncMethodAsync(1, scopeCount.ToString()); await SampleAsyncMethodAsync(2, scopeCount.ToString()); }); }

现在,它将运行3个任务,计数为3,每个任务将因此以 number 等于1、2和3的方式运行异步方法.

Now, it runs 3 tasks for 3 counts, and each task will consequently run asynchronous method with number equal to 1, 2, and 3.

更多推荐

C#链接ContinueWith不等待上一个任务完成

本文发布于:2023-11-24 05:34:29,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1624119.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:链接   ContinueWith

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!