【发布时间】:2022-03-05 21:03:37
【问题描述】:
我对并发(实际上是 C#)还很陌生。我在两个单独的目录中有一堆 csv 文件要读取,然后我想在读取文件后进行一些处理。该处理独立于其他数据读取和处理操作。完成所有处理后,我想更新 UI。同时 UI 也需要响应,因为我需要显示一个进度条。目前我有这样的事情:
private string _directoryA;
private string _directoryB;
// The user clicks the button
private void ButtonPressed()
{
Task.Run(() => DoJob());
}
private void DoJob()
{
var tasks = new List<Task>();
var watch = Stopwatch.StartNew();
tasks.Add(Task.Run(() => DoJobForDirectory(_directoryA).ContinueWith(t => Console.WriteLine("First Half");
tasks.Add(Task.Run(() => DoJobForDirectory(_directoryB).ContinueWith(t => Console.WriteLine("Second Half");
Task.WaitAll(tasks.ToArray());
watch.Stop();
Console.WriteLine($"Time Taken : {watch.ElapsedMilliseconds} ms.");
UpdateUI();
}
private void DoJobForDirectory(string directory)
{
var files = Directory.EnumerateFiles(directory, "*.csv");
var tasks = new List<Task>();
foreach (var file in files)
{
// Update the progress bar in the UI when a file has finished processing
tasks.Add(Task.Run(() => DoJobForFile(file)).ContinueWith(t => UpdateCounter++));
}
Task.WaitAll(tasks.ToArray());
}
private void DoJobForFile(string filePath)
{
ReadCSV();
ProcessData();
...
}
我觉得我在这里遗漏了一些东西。根据我的阅读,这个操作应该是 I/O 绑定的,因为之后的处理非常轻量级(一些 for 循环和分配)。所以我真的应该只使用异步等待,而不是 Task.Run()...?但是我想不出更好的方法来做到这一点。 ReadCSV() 来自一些没有异步版本的库。使用 Parallel.ForEach 也不会提高性能。有没有更好的方法来做到这一点(提高资源效率并获得更好的性能)?
另外,当我尝试只在一个目录上运行时,所用时间几乎是两个目录所需时间的一半。由于这些操作都是独立的,我想并行运行它们,因此处理两个目录的时间应该与处理单个目录的时间大致相同(或稍微多一点),但不会慢两倍。似乎无论我做了多少 Task.Run() ,我都会同时运行有限数量的线程(一些瓶颈)。我尝试将所有 Task.Run() 更改为 new Thread(),并观察到更多线程同时处于活动状态,但最终导致性能更差。这是为什么呢?
【问题讨论】:
标签: c# asynchronous concurrency