こんにちは。
本日はC#メモです。
概要
大量のファイル対して同様の処理を行いたい。
その処理には時間のかかる処理AとBが存在するとする。
非同期で処理をして効率よく処理が行えるようにする。
サンプルコード
メイン処理
メイン処理では
ファイルを取得して実際にファイルに対する処理を行うクラスをnewして呼び出します。
ファイルの取得はDirectory.EnumerateFiles
を使用しています。
Directory.EnumerateFiles
はファイルが見つかり次第返すので、
全てのファイルを検索するまで待機はしません。
あとは.Wait()
でタスクが完了するまで待機しています。
var files = Directory.EnumerateFiles(@"./text", "*.txt", SearchOption.AllDirectories); var manager = new FileManager(files); manager.Run().Wait();
ファイル処理
各ファイルごとに処理A、処理Bを非同期で実施しています。
Run()メソッドでは、
各ファイルのタスクをリストに格納し、Task.WhenAll()
を使用して
全ファイルのタスクが全て完了するのを待機しています。
Process()メソッドでは、
処理Aと処理Bのタスクをリストに格納し、Task.WhenAll()
を使用して
2つのタスクが全て完了するのを待機しています。
private class FileManager { private readonly IEnumerable<string> _files; public FileManager(IEnumerable<string> files) { this._files = files; } public Task Run() { var tasks = new List<Task>(); foreach (var file in this._files) { tasks.Add(this.Process(file)); } return Task.WhenAll(tasks); } private Task Process(string file) { var tasks = new List<Task>(); tasks.Add(Task.Run(() => { // 処理A var id = Thread.CurrentThread.ManagedThreadId; Console.WriteLine($"[処理A][{DateTime.Now.ToString("HH:mm:ss.fff")}] ThreadId={id} File={file}"); Thread.Sleep(TimeSpan.FromSeconds(3)); })); tasks.Add(Task.Run(() => { // 処理B var id = Thread.CurrentThread.ManagedThreadId; Console.WriteLine($"[処理B][{DateTime.Now.ToString("HH:mm:ss.fff")}] ThreadId={id} File={file}"); Thread.Sleep(TimeSpan.FromSeconds(5)); })); return Task.WhenAll(tasks); } }
実行結果
以下のファイルを用意して実行した結果です。
各ファイル、処理A、処理Bが非同期で実施されています。
- /text/aaa.txt
- /text/bbb.txt
[処理A][19:47:52.750] ThreadId=6 File=./text/aaa.txt [処理B][19:47:52.750] ThreadId=5 File=./text/bbb.txt [処理B][19:47:52.750] ThreadId=7 File=./text/aaa.txt [処理A][19:47:52.750] ThreadId=4 File=./text/bbb.txt
以上です。