2017-08-10 23 views
0

私は、parallel forループとhttpclientによるアプリケーションのクラッシュの問題を回避したいが、私はプログラミングの知識が限られているため、Web上の他の場所で提供されるソリューションを適用できない。私のコードは下に貼り付けられます。Parallel.ForとhttpclientがアプリケーションをクラッシュするC#

class Program 
    { 
     public static List<string> words = new List<string>(); 
     public static int count = 0; 
     public static string output = ""; 
     private static HttpClient Client = new HttpClient(); 
     public static void Main(string[] args) 
     { 
      //input path strings... 
      List<string> links = new List<string>(); 
      links.AddRange(File.ReadAllLines(input)); 
      List<string> longList = new List<string>(File.ReadAllLines(@"a.txt")); 
      words.AddRange(File.ReadAllLines(output1)); 
      System.Net.ServicePointManager.DefaultConnectionLimit = 8; 
      count = longList.Count; 
      //for (int i = 0; i < longList.Count; i++) 
      Task.Run(() => Parallel.For(0, longList.Count, new ParallelOptions { MaxDegreeOfParallelism = 5 }, (i, loopState) => 
      { 
       Console.WriteLine(i); 
       string link = @"some link" + longList[i] + "/"; 
       try 
       { 
        if (!links.Contains(link)) 
        { 
         Task.Run(async() => { await Download(link); }).Wait(); 
        } 
       } 
       catch (System.Exception e) 
       { 

       } 
           })); 
      //} 

     } 
     public static async Task Download(string link) 
     { 
      HtmlAgilityPack.HtmlDocument document = new HtmlDocument(); 
      document.LoadHtml(await getURL(link)); 
      //...stuff with html agility pack 
     } 
     public static async Task<string> getURL(string link) 
     { 
      string result = ""; 
      HttpResponseMessage response = await Client.GetAsync(link); 
      Console.WriteLine(response.StatusCode); 
      if(response.IsSuccessStatusCode) 
      { 
       HttpContent content = response.Content; 
       var bytes = await response.Content.ReadAsByteArrayAsync(); 
       result = Encoding.UTF8.GetString(bytes); 
      } 
      return result; 
     } 

    } 

は、たとえばthis oneのためのソリューションがありますが、私は私の主な方法でawaitキーワードを置く方法がわからない、と現在のプログラムは、単にTask.Run()前にその不在が原因で終了します。ご覧のとおり、私はすでにasync Download()メソッドに関する回避策をmainメソッドで呼び出す方法を適用しています。 私は、異なる並列スレッドでのhttpclientの同じインスタンスの使用にも疑問を抱いています。毎回httpclientの新しいインスタンスを作成する必要があるかどうかを私に教えてください。

答えて

0

コンソールアプリケーションでのどこかのタスクをブロックする必要があります。そうしないと、プログラムは完了する前に終了します。しかし、あなたは必要以上にこれをやっています。メインスレッドをブロックし、残りをasyncメソッドに委譲することを目指してください。あなたの例では

MainAsync(args).Wait(); 

を、MainからMainAsyncにすべてを移動します。良い習慣は、private async Task MainAsyc(args)のようなシグネチャを持つメソッドを作成しますが、あなたのプログラムロジックの「根性」を入れて、このようMainからそれを呼び出すことです。その後、あなたは好きなだけawaitを自由に使うことができます。 Task.RunParallel.Forは、I/Oバインドされた作業のために明示的に新しいスレッドを消費しています。これは、非同期の世界では不要です。代わりにTask.WhenAllを使用してください。

await Task.WhenAll(longList.Select(async s => { 
    Console.WriteLine(i); 
    string link = @"some link" + s + "/"; 
    try 
    { 
     if (!links.Contains(link)) 
     { 
      await Download(link); 
     } 
    } 
    catch (System.Exception e) 
    { 

    } 
})); 

一つの小さなシワががここにあります:あなたのMainAsyncメソッドの最後の部分は、このような何かを探して終わる必要があります。あなたの例は、5での並列性を抑制しています。これがまだ必要な場合は、TPL Dataflowは非同期世界での抑制された並列処理のための素晴らしいライブラリです。 Here's a simple example

HttpClientに関して、スレッド間で1つのインスタンスを使用すると、completely safehighly encouragedとなります。

+0

ありがとうございました。私は別のパッケージから同じような問題への他の答えの一つを使用して非同期foreachループを使用して解決しました。私は新しいスレッド・コールごとにhttpクライアントの新しいインスタンスを使用した後、速度が大幅に向上することを確認しました。 –

+0

Hmm。私は、HttpClientの多くのインスタンスがスピードアップの理由であることを非常に疑う。他の何かは異なっていなければなりません。私はあなたがしていることは最適ではないが、あなたが[あなたのソケットを使い果たしていない]場合(https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/)私はあなたに注意を喚起します大丈夫だよ。 –

関連する問題