好吧,所以基本上我有很多任务(10),我想同时启动所有任务并等待它们完成.完成后,我想执行其他任务.我读了很多有关此的资源,但是我无法针对我的具体情况...
这是我目前拥有的(代码已简化):
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);
}
}
所以我的问题是,当我等待任务完成时,
呼叫,它告诉我所有任务都结束了,即使它们都没有完成.我尝试添加
WhenAll
在我的飞天
当我输入继续任务时,数据不断从我以前的
Console.WriteLine
中输入
尚未真正完成。
我在这里做什么错了?
foreach
- 2021-1-111 #
- 2021-1-112 #
本质上,您是在混合两种不兼容的异步范例; 即
Parallel.ForEach()
和async-await
对于您想要的,执行一项或另一项.例如.你可以只用
Parallel.For[Each]()
并完全删除异步等待.Parallel.For[Each]()
仅在所有并行任务完成后才返回,然后您可以移至其他任务。代码也有其他一些问题:
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
p.ConfigureAwait(false)
随时待命,特别是如果您不想立即在UI线程中使用结果。如果要使用TPL在不同的线程中并行运行这些任务,则可能需要这样的东西:
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 }
这些方法仅并行处理少量代码:将方法排队到线程池中以及返回未完成的
Task
.同样,对于如此少量的任务,并行化可能比异步运行花费更多的时间.仅当您的任务在第一次等待之前做一些更长的(同步)工作时,这才有意义。在大多数情况下,更好的方法是:
public async Task RunTasks() { await Task.WhenAll(new [] { DoWork(), //... }); //Run the other tasks }
在您的代码中,我认为:
您不应将代码包装在
Task
中 在传递到Parallel.ForEach
之前您可以
await
Task.WhenAll
而不是使用ContinueWith
- 2021-1-113 #
DoWork
method是异步I / O方法.这意味着您不需要多个线程来执行其中的几个线程,因为在大多数情况下,该方法将异步等待I / O完成.一个线程就足以做到这一点。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 }
几乎不应该使用
Task
构造函数来创建新任务.要创建异步I / O任务,只需调用async
方法.要创建将在线程池线程上执行的任务,请使用Task.Run
.您可以阅读这篇文章,详细了解Task.Run
以及创建任务的其他选项。 - 2021-1-114 #
还可以在Task.whenAll
周围添加一个try-catch块。NB:抛出System.AggregateException的一个实例,该实例充当已发生的一个或多个异常的包装.这对于协调多个任务(例如Task.waitAll()和Task.waitAny())的方法很重要,以便AggregateException能够将所有异常包装在已发生的运行任务中。
try { Task.WaitAll(tasks.ToArray()); } catch(AggregateException ex) { foreach (Exception inner in ex.InnerExceptions) { Console.WriteLine(String.Format("Exception type {0} from {1}", inner.GetType(), inner.Source)); } }
相关问题
- c#:获取windows 8自动颜色主题的活动颜色c#netwpfwinapiwindows82021-01-12 01:28
- c#:遍历函数结果时,foreach如何工作?c#netforeach2021-01-11 17:26
- c#:PictureBox问题c#netwinformspicturebox2021-01-11 04:56
- c#:静态和实例方法同名?c#netoop2021-01-11 05:55
- c#:RequestUrlReferrer为空?c#netvisualstudiovisualstudio20082021-01-11 07:24
您几乎永远都不要使用
Task
直接构造函数.对于您而言,该任务只会触发您迫不及待的实际任务。您可以简单地致电
DoWork
然后取回任务,将其存储在列表中,然后等待所有任务完成.含义:但是,异步方法将同步运行,直到第一次等待未完成的任务.如果您担心该部分花费的时间太长,请使用
Task.Run
将其卸载到另一个ThreadPool
线程,然后存储 that 列表中的任务: