private static async Task ScanDirectoryAsync <T>(string path, ScannerOptions options, DependencyFound onDependencyFound, CancellationToken cancellationToken = default) where T : struct, IEnabledScannersArray { var fileSystem = options.FileSystem; using var enumerator = new ScannerFileEnumerator <T>(path, options); while (enumerator.MoveNext()) { var entry = enumerator.Current; var scanFileContext = new ScanFileContext(entry.FullPath, onDependencyFound, fileSystem, cancellationToken); try { for (var i = 0; i < options.Scanners.Count; i++) { if (!entry.Scanners.Get(i)) { continue; } var scanner = options.Scanners[i]; scanFileContext.ResetStream(); await scanner.ScanAsync(scanFileContext).ConfigureAwait(false); } } finally { await scanFileContext.DisposeAsync().ConfigureAwait(false); } } }
private static async Task ScanDirectoryParallelAsync <T>(string path, ScannerOptions options, DependencyFound onDependencyFound, CancellationToken cancellationToken = default) where T : struct, IEnabledScannersArray { var fileSystem = options.FileSystem; var filesToScanChannel = Channel.CreateBounded <FileToScan <T> >(new BoundedChannelOptions(10000) { AllowSynchronousContinuations = true, SingleWriter = true, SingleReader = false, FullMode = BoundedChannelFullMode.Wait, }); // Start enumerating var enumeratorTask = Task.Run(async() => { using var enumerator = new ScannerFileEnumerator <T>(path, options); while (enumerator.MoveNext()) { await filesToScanChannel.Writer.WriteAsync(enumerator.Current, cancellationToken).ConfigureAwait(false); } filesToScanChannel.Writer.Complete(); }, cancellationToken); // Parse files var tasks = new Task[options.DegreeOfParallelism + 1]; tasks[0] = enumeratorTask; Array.Fill(tasks, Task.Run(async() => { var reader = filesToScanChannel.Reader; while (await reader.WaitToReadAsync(cancellationToken).ConfigureAwait(false)) { while (reader.TryRead(out var entry)) { var scanFileContext = new ScanFileContext(entry.FullPath, onDependencyFound, fileSystem, cancellationToken); try { for (var i = 0; i < options.Scanners.Count; i++) { if (!entry.Scanners.Get(i)) { continue; } var scanner = options.Scanners[i]; scanFileContext.ResetStream(); await scanner.ScanAsync(scanFileContext).ConfigureAwait(false); } } finally { await scanFileContext.DisposeAsync().ConfigureAwait(false); } } } }, cancellationToken), startIndex: 1, options.DegreeOfParallelism); await Task.WhenAll(tasks).ConfigureAwait(false); }
private static async IAsyncEnumerable <Dependency> ScanDirectoryParallelAsync <T>(string path, ScannerOptions options, [EnumeratorCancellation] CancellationToken cancellationToken = default) where T : struct, IEnabledScannersArray { var fileSystem = options.FileSystem; var filesToScanChannel = Channel.CreateBounded <FileToScan <T> >(new BoundedChannelOptions(1000) { AllowSynchronousContinuations = true, SingleWriter = true, SingleReader = false, FullMode = BoundedChannelFullMode.Wait, }); var dependenciesChannel = Channel.CreateUnbounded <Dependency>(new UnboundedChannelOptions { AllowSynchronousContinuations = true, SingleWriter = false, SingleReader = true, }); // Start enumerating var enumeratorTask = Task.Run(async() => { using var enumerator = new ScannerFileEnumerator <T>(path, options); while (enumerator.MoveNext()) { await filesToScanChannel.Writer.WriteAsync(enumerator.Current, cancellationToken).ConfigureAwait(false); } filesToScanChannel.Writer.Complete(); }, cancellationToken); // Parse files var exceptions = new ConcurrentBag <Exception>(); var tasks = new Task[options.DegreeOfParallelism]; Array.Fill(tasks, Task.Run(async() => { var reader = filesToScanChannel.Reader; while (await reader.WaitToReadAsync(cancellationToken).ConfigureAwait(false)) { while (reader.TryRead(out var entry)) { var scanFileContext = new ScanFileContext(entry.FullPath, d => dependenciesChannel.Writer.WriteAsync(d, cancellationToken), fileSystem, cancellationToken); try { for (var i = 0; i < options.Scanners.Count; i++) { if (!entry.Scanners.Get(i)) { continue; } var scanner = options.Scanners[i]; scanFileContext.ResetStream(); await scanner.ScanAsync(scanFileContext).ConfigureAwait(false); } } finally { await scanFileContext.DisposeAsync().ConfigureAwait(false); } } } }, cancellationToken)); var whenAllTasks = Task.WhenAll(tasks); var writerCompleteTask = whenAllTasks.ContinueWith(_ => dependenciesChannel.Writer.Complete(), cancellationToken); await foreach (var value in dependenciesChannel.Reader.ReadAllAsync(cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false)) { yield return(value); } await writerCompleteTask.ConfigureAwait(false); await whenAllTasks.ConfigureAwait(false); }