.NET 8 Debian Docker挂载Windows共享文件百万级处理性能优化
问题背景
我正在开发一个运行于Debian Docker容器中的.NET 8控制台应用,该应用需扫描Linux挂载的Windows共享文件系统,高效处理2-3百万个文件。
当前实现方案
var fileBatches = PartitionFiles(Directory.EnumerateFiles(scanPath, "*", SearchOption.AllDirectories), 10000); await ProcessFileBatchesOptimizedAsync(fileBatches, cancellationToken);
分片逻辑
private static IEnumerable<List<string>> PartitionFiles(IEnumerable<string> files, int batchSize) { List<string> batch = new List<string>(batchSize); foreach (var file in files) { batch.Add(file); if (batch.Count >= batchSize) { yield return batch; batch = new List<string>(batchSize); } } if (batch.Count > 0) { yield return batch; } }
处理逻辑
private async Task ProcessFileBatchesOptimizedAsync(IEnumerable<List<string>> fileBatches, CancellationToken cancellationToken) { List<Task> tasks = new List<Task>(); foreach (var fileBatch in fileBatches) { tasks.Add(Task.Run(async () => { await ExtractFileMetadataAndSaveToDB(fileBatch); }, cancellationToken)); } await Task.WhenAll(tasks); }
核心问题
PartitionFiles中的yield return成为性能瓶颈,ProcessFileBatchesOptimizedAsync中的foreach需等待分片器生成批次,导致文件处理任务完成速度快于批次生成,任务近乎串行执行,并行失去意义。
已尝试方案
- 生产者-消费者模型:性能类似,生产者(批次生成)速度慢于消费者(文件处理)。
- 递归遍历目录(
Directory.GetDirectories+Directory.GetFiles(directory)):性能更差,需分两步获取目录和文件。 - 预加载所有文件:性能略有提升,但内存占用过高,处理百万级文件存在风险。
var allFiles = Directory.EnumerateFiles(scanPath, "*", SearchOption.AllDirectories).ToList(); var fileBatches = PartitionFilesEager(allFiles, 10000);
需求
寻求一种更高效的方案,在不将所有文件路径加载到内存的前提下,扫描并并发处理2-3百万个文件,避免yield瓶颈。
补充信息
ExtractFileMetadataAndSaveToDB中,通过foreach循环处理每批1万个文件,使用FileInfo获取文件元数据(名称、创建时间、修改时间等);准备好1万条元数据后,通过SemaphoreSlim(Math.Max(1, Environment.ProcessorCount / 2))控制,以5千条为批次调用BulkCopyAsync写入数据库。
内容的提问来源于stack exchange,提问作者Himanshu Garg
相关产品推荐
相关产品推荐

