Я не совсем уверен в эффективном способе сделать это. У меня есть файлы, в которых содержимое файла указывает на другие файлы, например:
A
|-- B
| |-- C
| |-- D
| |-- E
|
|-- F
|-- C
G
|-- H
| |-- I
|
|-- D
| |-- E
|
|-- J
Это продолжается для сотен тысяч и тысяч файлов; к счастью, глубина зависимостей очень мала, но, ради аргументов, потенциально она может быть N-уровневой, без циклических циклов. Моя цель - узнать полную зависимость каждого файла (сплющенного). Например:
- A: (B, C, D, E, F) -- Обратите внимание, что «C» указан только один раз.
- B: (C, D, E)
- C: ()
- D: (E)
- E: ()
- F: (C)
- G: (D, E, H, I, J)
- и т. д.
Сначала я начал с создания некоторой модели для отслеживания этой информации:
public class FileData
{
public string FilePath { get; set; }
public ISet<FileInfo> DependentUpon { get; set; }
}
Конечно, затем я создал List<FileData>
для хранения обработанных файлов. Синхронное сканирование содержимого файлов для построения этого дерева зависимостей (а затем его выравнивание) заняло бы слишком много времени, поэтому я исследовал использование async/await, которое помогло ускорить процесс, но я хочу сделать его еще быстрее, прежде чем высвобождение его в производственной среде.
Моя попытка async/await намного быстрее, но все еще недостаточно эффективна.
public async Task<ICollection<FileData>> ProcessAsync(IEnumerable<FileInfo> files)
{
var mappings = new Dictionary<FileInfo, FileData>();
foreach (var file in files)
{
// Static Method that constructs an instance of the class
// and utilizes async I/O to read the file line-by-line
// to build any first level dependencies.
var info = await FileData.CreateAsync(file);
// Update progress + Other Properties
mappings.Add(file, info);
}
// Go through the list and recursively add to the dependencies
foreach (var item in list)
{
foreach (var dependency in GetAllDependencies(item, mappings))
{
file.DependentUpon.Add(dependency);
}
}
}
IEnumerable<FileInfo> GetAllDependencies(FileData data, IDictionary<FileInfo, FileData> mappings)
{
foreach (var file in info.DependentUpon)
{
yield return file;
foreach (var child in GetAllDependencies(mappings[file], mappings))
{
yield return child;
}
}
}
Это, конечно, несколько асинхронно, но все же очень синхронно и медленно, когда я пытаюсь получить иерархическую структуру (сплющенную). Я пытаюсь реорганизовать решение, чтобы оно работало намного быстрее, используя преимущества async/await при иерархическом поиске. Пока у меня есть только псевдоописание, и я понятия не имею, возможно ли это или как это правильно реализовать:
Создайте словарь FileInfo
и Task<FileData>
(так что я больше не жду создания экземпляров класса). После сканирования файла на наличие DependentUpon первого уровня я нахожу совпадающие задачи и продолжаю свою текущую задачу только после того, как эти задачи будут выполнены. Конечно, эти задачи имеют одни и те же инструкции, поэтому они будут помечены как завершенные только после завершения их зависимостей. Я хочу запустить все задачи одновременно. Например (просто пример, я не могу предсказать, какая задача будет завершена, когда):
- Начать задачу А
- Начать задачу Б
- Сканировать файл A, DependentUpon (B, F)
- Начать задачу C
- Сканировать файл B, DependentUpon (C, D)
- Задача A Дождитесь завершения задач B и F.
- Начать задачу D
- Сканировать файл C
- ...
- Задача D Дождитесь завершения задачи E.
- Сканировать файл E, DependentUpon ()
- Задача E завершена
- Задача D завершена
- Задача C завершена
- Задача Б выполнена.
- Начать задачу J
- Задача F выполнена.
- Задача А выполнена.
- ...
- Все задачи выполнены
await
внутри циклаforeach
? Не могли бы вы добавитьCreateAsync
задач в список, а затемTask.WhenAll
после цикла? - person jamespconnor   schedule 13.01.2016