1

Hello I have the following code that creates a task. Then sets it to start. The task is meant to add a response to the ConcurrentBag list. But the await does not seem to be waiting for all the tasks to complete. But they are being marked as completed. There is only one task in the list. It works fine when using Task.Run!

public async void RunT1() { DoesNotWork(); } public async void RunT2() { DoesWork(); } public async void DoesNotWork() { ConcurrentBag<string> concurrentBag = new ConcurrentBag<string>(); List<Task> taskList = new List<Task>(); Task task1 = new Task(async () => { var xml = await LongWorkingMethod(); concurrentBag.Add(xml); }); taskList.Add(task1); taskList[0].Start(); await Task.WhenAll(taskList); if (concurrentBag.Count > 0) //concurrentBag is empty, //even though the task has finished { Debug.Print("success"); } } public async void DoesWork() { ConcurrentBag<string> concurrentBag = new ConcurrentBag<string>(); List<Task> taskList = new List<Task>(); Task task1 = Task.Run(async () => { var xml = await LongWorkingMethod(); concurrentBag.Add(xml); }); taskList.Add(task1); await Task.WhenAll(taskList); if (concurrentBag.Count > 0) //concurrentBag is NOT empty { Debug.Print("success"); } } 

1 Answer 1

8

There's almost never a reason to use the Task constructor directly.

In your case the Task constructor doesn't support an async delegate (i.e. Action instead of Func<Task>) and when you pass one as a parameter is it treated as async void.

That means that calling Start "fires and forgets" the delegate and it can't wait for the asynchronous operation inside it to complete because there's no Task to await on.

var task = new Task(async () => await Task.Delay(1000)); task.Start(); await task; // completes immediately 

Use Task.Run in cases where you need to run a new Task. Task.Run, as you see, does support an async delegate correctly and waits for the entire operation to complete

var task = Task.Run(async () => await Task.Delay(1000)); await task; // completes after 1000 milliseconds 
Sign up to request clarification or add additional context in comments.

4 Comments

I want to run them later 2 at a time. Yea that makes sense. But Doesnt seem there is an option to process my taskList say using 2 threads only. It will use up all the threads if i add them to the list using Task.Run
@lymber if you want to prepare them at first and execute them later, I would simply store a list of Func<Task> and when you invoke them they start running.
Yes but i dont want them too all start running. Just run two concurrently , wait for those two to run, then do the next two until the list is consumed.
@lymber then only invoke 2 of these lambdas, await the returned tasks, and invoke the next 2. Also, you should probably take a look at TPL Dataflow's ActionBlock

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.