pzaj
pzaj

Reputation: 1092

C# How to get multiple tasks to start and then await them

I'm struggling with making my tasks run. I believe they don't start and await never returns, that way my application never runs further. It's meant to process multiple data sets (known at the moment of execution) and therefore I add them using a loop, it looks this way:

foreach(IGrouping<enumType, Item> group in lp)
{
    Task<ProcessedItem> t = new Task<ProcessedItem>(
        () => ProcessItems(group.ToList(), group.Key));
    tasks.Add(t);
}

await Task.WhenAll(tasks);

(...)

And it stops at Task.WhenAll. I think they're not started at all, I have a similar code within another method, but there I pass the function to the task directly:

Task<ReturnType>(Func);

Which I believe causes the difference, I cannot pass it this way here due to parameters. How should I modify my code to make it work? Should I explicitly start each task? Wouldn't that break the await keyword if tasks finishes before the await?

Upvotes: 1

Views: 975

Answers (2)

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149646

I think they're not started at all

You are most certainly correct. new Task() returns a "cold task", which is a task that hasn't started making you explicitly call Task.Start() on it. The docs spell this out clearly:

Rather than calling this constructor, the most common way to instantiate a Task object and launch a task is by calling the static Task.Run(Action) or TaskFactory.StartNew(Action) method. The only advantage offered by this constructor is that it allows object instantiation to be separated from task invocation.

This is one of the reasons why you shouldn't use the Task constructor, and instead use the factory methods, that provide you with a "hot task" which is one that is already started. Here, Task.Run would be appropriate:

var tasks = lp.Select(group => Task.Run(() => ProcessItems(group.ToList(), group.Key)));
await Task.WhenAll(tasks);

Upvotes: 6

Suren Srapyan
Suren Srapyan

Reputation: 68685

For Starting you need to call Start() method.And your method in which you use this fragment must be assigned with async keyword

foreach(IGrouping<enumType, Item> group in lp)
{
    Task<ProcessedItem> t = new Task<ProcessedItem>(() => ProcessItems(group.ToList(), group.Key));

    t.Start();
    tasks.Add(t);
}

await Task.WhenAll(tasks);

(...)

It will wait when all tasks inside then tasks will finish their exection

Or you can use instead of Start() method Task.Run() method

foreach(IGrouping<enumType, Item> group in lp)
{
    Task<ProcessedItem> t = Task.Run(() => ProcessItems(group.ToList(), group.Key));

    tasks.Add(t);
}

await Task.WhenAll(tasks);

(...)

Upvotes: 3

Related Questions