【问题标题】:Waiting for Tasks to finish in a list with ContinueWith使用 ContinueWith 在列表中等待任务完成
【发布时间】:2017-04-11 23:54:57
【问题描述】:

更新 添加了在taskList中添加的缺失代码

我有一个任务列表,我正在等待..

var files = Directory.GetFiles(myFilesDirectory);
var listOfTasks = new List<Tasks>();
files.ToList().ForEach(file => {
    var localFile = file // to avoid any closure issue
    listOfTasks.Add(ProcessMyFileTask(localFile));
});
await Task.WhenAll(listOfTasks.ToArray());
Console.WriteLine("All done!");

这是 ProcessMyFileTask

private async Task<List<string>> ProcessMyFileTask(string filePath)
    {
        using (var streamReader = File.OpenText(filePath))
        {
            string line;
            if ((line = await streamReader.ReadLineAsync()) != null)
            {
                return DumpHexInLog(line);
            }
            return null;
        }
    }

在处理完所有文件后会显示该消息。但是如果我添加一个延续任务,像这样..

var files = Directory.GetFiles(myFilesDirectory);
var listOfTasks = new List<Tasks>();
files.ToList().ForEach(file => {
    var localFile = file // to avoid any closure issue
    listOfTasks.Add(ProcessMyFileTask(localFile).ContinueWith(list => 
            ValidateHexDumpsTask(list.Result, localFile)));
});
await Task.WhenAll(listOfTasks.ToArray());
Console.WriteLine("All done!");

那么等待什么任务呢?我的意思是"All Done!" 会在所有ProcessMyFileTask 完成后出现吗?还是会在所有ValidateHexDumpsTask 都完成之后来?

当我测试它时,它出现在 ValidateHexDumpsTask 之后,但我不确定是否总是如此,因为这可能是由于某些线程条件或诸如此类。

【问题讨论】:

  • 第一点:你不需要那个localFile = file。在这种情况下,file 是 lambda 表达式的参数。它没有捕获其他任何东西。
  • 接下来,不清楚你在哪里填充listOfTasks。当我们只能看到伪代码时,真的很难提供帮助。请改为提供minimal reproducible example。 (当然,它们不必是真实文件 - 只是字符串就可以了......)
  • 这仍然是伪代码 - 由于forEach 不是ForEach,它无法编译。再次,请提供minimal reproducible example
  • 它仍然不完整。如果是这样,我可以将代码复制并粘贴到一个全新的文件中,编译并运行它。
  • 请提供一个最小、完整和可验证的示例?任何最终解决方案?

标签: c# multithreading async-await task


【解决方案1】:

只有当ProcessMyFiles 方法和ValidateHexDumps 都完成时才会完成。

但是,不推荐使用ContinueWith。这是一个低级的、危险的 API。你应该改用await

var files = Directory.GetFiles(myFilesDirectory);
var listOfTasks = files.Select(ProcessAndValidateAsync);
await Task.WhenAll(listOfTasks);
Console.WriteLine("All done!");


async Task ProcessAndValidateAsync(string file)
{
  var list = await ProcessMyFileTask(localFile);
  ValidateHexDumps(list, localFile);
}

【讨论】:

  • 否; ContinueWith 返回一个代表延续的新任务。
  • ContinueWith is dangerous 的原因与StartNew is dangerous 相同:简而言之,1)它不理解async; 2) 它使用TaskScheduler.Default以外的默认调度程序; 3) 它没有适合异步任务的选项默认值 (DenyChildAttach)。
【解决方案2】:

WhenAll 将在 ValidateHexDumps 完成对每个项目的运行后完成。

ContinueWith 返回一个Task,它表示延续的完成,而不是作为延续的任务的完成。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-24
    • 1970-01-01
    • 2014-05-07
    • 2014-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多