【发布时间】:2018-03-17 12:07:48
【问题描述】:
我遇到了一个问题,即场景 1 的运行速度比场景 2 慢,尽管场景 1 似乎应该运行得更快,因为它不仅在更高级别打开任务,而且在内部级别打开任务。有点像父子概念(我知道父/子实际上并没有发生,因为我相信任务都在同一级别运行)。场景 2 只是在更高级别创建任务,并且整体运行速度更快。我能想到的唯一一件事是运行更少的任务会更快,因此可以并行处理所有内容,而不是尝试打开更多任务,这很可能会导致在 4 核(8 线程)CPU 上等待。
我想弄清楚场景 2 是否总是会更快,或者是否有更好的方法来编写场景 1,使其实际上比场景 2 更快。
场景 1(有嵌套任务):
public void MainFunction() {
IList<Task<ProductMaster>> tasks = new List<Task<ProductMaster>>();
foreach (var x in products)
{
Task<ProductMaster> prodMaster = Task.Factory.StartNew<ProductMaster>(() => RunProductMasterCode(param1, param2));
tasks.Add(prodMaster);
}
foreach (Task<ProductMaster> tsk in tasks)
{
ProductMaster prodMaster = tsk.Result;
// COMPLEX CODE HERE THAT RELIES ON tsk.Result
}
}
public ProductMaster RunProductMasterCode(int param1, int param2) {
IList<Task<ProductSub>> tasks = new List<Task<ProductSub>>();
foreach (var x in subProducts)
{
Task<ProductSub> prodSub = Task.Factory.StartNew<ProductSub>(() => RunProductSubCode(param1));
tasks.Add(prodSub);
}
foreach (Task<ProductSub> tsk in tasks)
{
ProductSub prodSub = tsk.Result;
// COMPLEX CODE HERE THAT RELIES ON tsk.Result
}
}
public ProductSub RunProductSubCode(int param1) {
// COMPLEX CODE HERE
}
场景 2(有单层任务通知我没有在 RunProductMasterCode() 中创建任务):
public void MainFunction() {
IList<Task<ProductMaster>> tasks = new List<Task<ProductMaster>>();
foreach (var x in products)
{
Task<ProductMaster> prodMaster = Task.Factory.StartNew<ProductMaster>(() => RunProductMasterCode(param1, param2));
tasks.Add(prodMaster);
}
foreach (Task<ProductMaster> tsk in tasks)
{
ProductMaster prodMaster = tsk.Result;
// COMPLEX CODE HERE THAT RELIES ON tsk.Result
}
}
public ProductMaster RunProductMasterCode(int param1, int param2) {
foreach (var x in subProducts)
{
// NO THREADING HERE
var prodSub = RunProductSubCode(param1);
}
}
public ProductSub RunProductSubCode(int param1) {
// COMPLEX CODE HERE
}
【问题讨论】:
-
prodSub是foreach循环的本地。复杂的代码应该在循环内吗? -
@IanMcLaird 抱歉,我不得不对我的代码进行一些调整。我忘记表明我正在添加到任务列表中,然后在调用.Result 时循环遍历它。另外删除了您正在谈论的评论,因为它不应该出现在场景 2 中。
-
为什么不能将复杂代码作为每个任务的最后一步调用?复杂的代码是否要求所有任务都已完成?
-
@IanMcLaird 每次看到复杂代码时都要纠正它依赖于完成所有任务。所以不,我不能把它称为每项任务的最后一步。
-
Task.WhenAll()可以帮助解决这个问题,但我不确定你能否做得比现在更好。您可能刚刚发现进一步将任务分解为线程只会增加开销。
标签: c# multithreading performance asynchronous async-await