2

私の実際のプログラムはこれよりも洗練されていますが、単純化しようとしました。

では、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 も可能ですが、同じ問題がよくあると思います。

4

2 に答える 2

1

私は物事を間違って構造化していると思いますが、物事を再編成する方法がわかりません。

それは本当だと思います。考えられる解決策は次のとおりです。2番目の部分だけでなく、計算全体を としてTaskリストに保存します。

async Task ProcessSingleUrlInner(string url) {  
    var web = new HttpClient();  
    var WebPageContents = await web.GetStringAsync(url);  
    Task t = Task.Run(() => ProcessWebPage(WebPageContents);  
    await t;
}

void ProcessSingleUrl(string url) {
var t = ProcessSingleUrlInner(url);
TaskList.Add(t);
}

このリストのすべてのタスクを待機すると、すべてが完了することが保証されます。おそらく、このアイデアを正確なニーズに適合させる必要があります。

于 2013-01-11T16:13:11.150 に答える
0

IEnumerable<string>URLのリストを何らかの形で取得していると思います。

LINQ を使用して各 URL を に変換してTaskから、awaitすべてを完成させることができます。

async Task ProcessUrls(IEnumerable<string> urls)
{
  var tasks = urls.Select(async url =>
  {
    var web = new HttpClient();  
    var WebPageContents = await web.GetStringAsync(url);  
    await Task.Run(() => ProcessWebPage(WebPageContents);
  });
  await Task.WhenAll(tasks);
}

このソリューションを使用し、エラーのある複数の異なる URL がある場合、Task.WhenAllそれらのエラーの 1 つだけが報告されることに注意してください。

于 2013-01-11T18:21:16.270 に答える