我应该在目录和子目录中处理大约8000个文件。如何使用线程/任务轻松处理每个文件并等待所有文件?
目前,我使用此代码
var files = Directory.EnumerateFileSystemEntries(@"E:\Nouveau dossier (2)",
"*.*", SearchOption.AllDirectories);
foreach (var f in files)
{
ToDo(f);
}
然而,它非常慢。
答案 0 :(得分:3)
尝试使用Parallel.ForEach方法。但是,由于IO是bootleneck,它不会保证任何性能提升。
Parallel.ForEach(files, (f) => {
ToDo(f);
});
答案 1 :(得分:3)
请记住,任何正确答案都必须处理两件事。
现在,这两部分中哪一部分需要更多时间?如果它正在读取文件,并且通常情况就是这样,那么使用多个内核就没有任何帮助。他们仍然需要等待数据进入。
我给你的建议是做一个实验。不处理文件,只读它们。使您的ToDo()
函数只需将文件读取到最后。这是整个工作的最短时间。
然后尝试并行读取文件,但要准备好看到它需要比以前更多的时间......你可以这样做:
Parallel.ForEach(files, ReadToEnd);
这假设ReadToEnd()
是您的测试函数,它只读取文件的内容。
答案 2 :(得分:1)
您可以使用Parallel课程。
请在下面找到一个例子:
class Program
{
static void Main(string[] args)
{
var files = Directory.EnumerateFileSystemEntries(@"C:\Users\Myleo\Pictures", "*.*", SearchOption.AllDirectories);
var program = new Program();
var result = program.ProcessInParallelWithCounter(files);
Console.WriteLine("count: {0}", result);
#if DEBUG
Console.ReadKey();
#endif
}
private void ProcessInParallel(IEnumerable<string> files)
{
// process
Parallel.ForEach(files, Process);
}
private int ProcessInParallelWithCounter(IEnumerable<string> files)
{
// process and count
var counter = 0;
Parallel.ForEach(
files,
() => 0,
(file, loopState, localCount) =>
{
Process(file);
return ++localCount;
},
count => Interlocked.Add(ref counter, count));
return counter;
}
private void Process(string file)
{
// your code.
}
}
答案 3 :(得分:1)
刚刚关闭,这里有几种方法可以使用多个线程来更好地利用CPU功率来加速处理,假设这是瓶颈所在。例如,如果瓶颈是磁盘I / O,则可能无法提高性能。
答案 4 :(得分:0)
因为读取文件是IO操作,所以async/await
方法似乎是此任务的最佳方法。
在IO读取或写入文件时,您不需要浪费线程等待。读取或写入文件的操作包含&#34; waiting&#34;用于IO设备的响应。创建无效的单独线程 - &gt;只有等待是浪费资源,没有为您的应用程序提供任何价值。
通过使用async/await
,您可以只使用一个线程执行相同的工作。当第一个任务等待文件被读取时,将启动另一个任务,依此类推。
您可以让ToDo
方法异步工作
public async Task ToDoAsync(string file)
{
using (var fileReader = File.OpenText(file))
{
var allFile = await fileReader.ReadToEndAsync();
// and do something
}
}
然后使用它
var files = Directory.EnumerateFileSystemEntries(@"E:\Nouveau dossier (2)", "*.*", SearchOption.AllDirectories);
var tasks = new List<Task>();
foreach (var f in files)
{
var task = ToDoAsync(f);
tasks.Add(task);
}
await Task.WhenAll(tasks.ToArray());
因此,为了获得更好的性能和更好的资源使用,您需要将逻辑划分为两部分,如@Zoran答案所述。
答案 5 :(得分:0)
您可以在单独的任务中运行ToDo
var files = Directory.EnumerateFileSystemEntries(@"E:\Nouveau dossier (2)", "*.*", SearchOption.AllDirectories);
List<Task> tasks = new List<Task>();
foreach (var f in files)
{
var local = f;
var tast = Task.Run(() => ToDo(local));
tasks.Add(task);
}
Task.WhenAll(tasks.ToArray());