Проблема real заключается в том, как обрабатывать несколько файлов параллельно. ProcessMatFiles
возвращает Task
уже, и я предполагаю, что он не запускает ничего тяжелого в потоке вызывающего. Эта задача может быть сохранена в списке tasks
. Этот список можно ожидать без блокировки с помощью
await Task.WhenAll(tasks);
. Лучшим решением было бы преобразование всего цикла в запрос LINQ, который возвращает задачи и ожидает его.
var tasks = from var directory in matFileDirectories
let dir=new DirectoryInfo(directory)
let files=dir.GetFiles()
select ProcessMatFiles(dir.Name, files));
await Task.WhenAll(tasks);
Проблема в том, что перечисление файлов в папке само по себе дорого, и GetFiles()
, или использование EnumerateFiles().ToList()
, должно ждать завершения перечисления. Было бы лучше, если бы ProcessMatFiles
получил объект DirectoryInfo и перечислил файлы в отдельном потоке .
Еще одним улучшением будет обработка файлов один за другим:
var tasks = from var directory in matFileDirectories
let dir=new DirectoryInfo(directory)
from file in dir.EnumerateFiles()
select ProcessMatFile(dir.Name, file));
Возможно улучшить это, если знать, что делает ProcessMatFiles
, например, использовать блоки потока данных или каналы для регулирования и использовать определенное количество задач, разбивая процесс на несколько одновременных шагов и т. Д.
Обновление
Поскольку это операция загрузки файла, каждый файл является отдельной асинхронной операцией. Большинство проверок можно удалить при работе с объектами DirectoryInfo и FileInfo.
Метод загрузки должен быть следующим:
async Task Upload(FileInfo file)
{
var folder=file.Directory.Name;
var blob = _cloudBlobContainer.GetBlockBlobReference(${"textures/{folder}/{file.Name}";
if (!await blob.ExistsAsync())
{
await blob.UploadFromFileAsync(file.FullName);
}
}
Запрос на создание задачи может быть упрощен до:
var tasks = from var directory in matFileDirectories
let dir=new DirectoryInfo(directory)
from file in dir.EnumerateFiles()
select UploadFile(file);
await Task.WhenAll(tasks);
Это попытается отключить все операции загрузкитак быстро, как файлы могут быть повторены. Это может затопить сеть. Одним из решений является использование ActionBlock , который будет использовать только 8 задач одновременно для загрузки файлов. Ограничение также накладывается на входной буфер, чтобы избежать его заполнения, например, 1000 элементами FileInfo:
var options=new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 8, //Only 8 concurrent operations
BoundedCapacity=64 //Block posters if the input buffer has too many items
} ;
var block=new ActionBlock<FileInfo>(async file=>UploadFile(file),options);
var files = from var directory in matFileDirectories
let dir=new DirectoryInfo(directory)
from file in dir.EnumerateFiles()
select file;
foreach(var file in files)
{
//Wait here if the input buffer is full
await block.SendAsync(file);
}
block.Complete();
//Wait for all uploads to finish
await block.Completion;