私の実際のプログラムはこれよりも洗練されていますが、単純化しようとしました。
では、URL のリストを含むファイルを読んでいるとしましょう。各URLからHTMLをダウンロードして加工したい。処理が少し複雑かもしれないので、別スレッドでやってほしいです。
基本的な問題は、すべての処理がいつ完了したかを知る方法です。たとえば、すべての URL が処理される前にユーザーがプログラムを閉じようとした場合、プログラムを終了せずにメッセージを表示したいと考えています。または、すべての URL が処理されたらすぐに (おそらく MsgBox("Done") メッセージで) プログラムを終了したいと考えています。
コードを次のようにしたいと思います (URL を読み取ってこのルーチンを呼び出す外側のループがあると仮定します)...
List<Task> TaskList = new List<Task>();
async void ProcessSingleUrl(string url) {
var web = new HttpClient();
var WebPageContents = await web.GetStringAsync(url);
Task t = Task.Run(() => ProcessWebPage(WebPageContents);
TaskList.Add(t);
}
上記のコードは非常に高速に実行され (非同期メソッドはすぐに実行されます)、呼び出し元にすぐに戻ります。
しかし、その時点では、GetStringAsync が完了するまでタスクは定義されず、それまでに何も (またはほんの少ししか) 完了していない可能性があるため、TaskList にエントリがまったくない可能性があります。そう
Task.WaitAll(TaskList.ToArray());
必要な方法で機能しません。
絶対に必要な場合は、最初にすべての URL を読み込んで、予想されるタスクの数を知ることができますが、より洗練されたソリューションを望んでいます。
await の直前にカウンターをインクリメントできると思いますが、それは少しぎこちなく感じます。
私は物事を間違って構造化していると思いますが、物事を再編成する方法がわかりません。
注: 私は Task.Run に慣れていません。古き良き QueueWorkItem も可能ですが、同じ問題がよくあると思います。