Executing tasks in parallel
Executing tasks in parallel
问题
Ok, so basically I have a bunch of tasks (10) and I want to start them all at the same time and wait for them to complete. When completed I want to execute other tasks. I read a bunch of resources about this but I can't get it right for my particular case...
Here is what I currently have (code has been simplified):
public async Task RunTasks()
{
var tasks = new List<Task>
{
new Task(async () => await DoWork()),
//and so on with the other 9 similar tasks
}
Parallel.ForEach(tasks, task =>
{
task.Start();
});
Task.WhenAll(tasks).ContinueWith(done =>
{
//Run the other tasks
});
}
//This function perform some I/O operations
public async Task DoWork()
{
var results = await GetDataFromDatabaseAsync();
foreach (var result in results)
{
await ReadFromNetwork(result.Url);
}
}
So my problem is that when I'm waiting for tasks to complete with the WhenAll
call, it tells me that all tasks are over even though none of them are completed. I tried adding Console.WriteLine
in my foreach
and when I have entered the continuation task, data keeps coming in from my previous Task
s that aren't really finished.
What am I doing wrong here?
回答1
You should almost never use the Task
constructor directly. In your case that task only fires the actual task that you can't wait for.
You can simply call DoWork
and get back a task, store it in a list and wait for all the tasks to complete. Meaning:
tasks.Add(DoWork());
// ...
await Task.WhenAll(tasks);
However, async methods run synchronously until the first await on an uncompleted task is reached. If you worry about that part taking too long then use Task.Run
to offload it to another ThreadPool
thread and then store that task in the list:
tasks.Add(Task.Run(() => DoWork()));
// ...
await Task.WhenAll(tasks);
回答2
If you want to run those task's parallel in different threads using TPL you may need something like this:
public async Task RunTasks()
{
var tasks = new List<Func<Task>>
{
DoWork,
//...
};
await Task.WhenAll(tasks.AsParallel().Select(async task => await task()));
//Run the other tasks
}
These approach parallelizing only small amount of code: the queueing of the method to the thread pool and the return of an uncompleted Task
. Also for such small amount of task parallelizing can take more time than just running asynchronously. This could make sense only if your tasks do some longer (synchronous) work before their first await.
For most cases better way will be:
public async Task RunTasks()
{
await Task.WhenAll(new []
{
DoWork(),
//...
});
//Run the other tasks
}
To my opinion in your code:
-
You should not wrap your code in
Task
before passing toParallel.ForEach
. -
You can just
await
Task.WhenAll
instead of usingContinueWith
.
回答3
Essentially you're mixing two incompatible async paradigms; i.e. Parallel.ForEach()
and async-await
.
For what you want, do one or the other. E.g. you can just use Parallel.For[Each]()
and drop the async-await altogether. Parallel.For[Each]()
will only return when all the parallel tasks are complete, and you can then move onto the other tasks.
The code has some other issues too:
-
you mark the method async but don't await in it (the await you do have is in the delegate, not the method);
-
you almost certainly want
.ConfigureAwait(false)
on your awaits, especially if you aren't trying to use the results immediately in a UI thread.
回答4
The DoWork
method is an asynchronous I/O method. It means that you don't need multiple threads to execute several of them, as most of the time the method will asynchronously wait for the I/O to complete. One thread is enough to do that.
public async Task RunTasks()
{
var tasks = new List<Task>
{
DoWork(),
//and so on with the other 9 similar tasks
};
await Task.WhenAll(tasks);
//Run the other tasks
}
You should almost never use the Task
constructor to create a new task. To create an asynchronous I/O task, simply call the async
method. To create a task that will be executed on a thread pool thread, use Task.Run
. You can read this article for a detailed explanation of Task.Run
and other options of creating tasks.
作者:Chuck Lu GitHub |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2019-07-04 shell script operate the date
2019-07-04 Running .sh scripts in Git bash
2019-07-04 What is the !! (not not) operator in JavaScript?
2019-07-04 JavaScript-Load-Image
2019-07-04 jquery .each
2019-07-04 JavaScript json loop item in array
2019-07-04 Make jQuery throw error when it doesn't match an element