2011-03-20 4 views
2

私はまだこのスレッディングに夢中です。私は50000のURLを持っていると言うと、10個のURLをまとめて処理するように、これらのURLの内容を同時に取得したいとします。これらのURLの1つが処理を終了すると、リスト内のすべてのURLの処理が終了するまで、キューリストから別の1が追加されます。今どのように私はC#のと...ここで私はすべてのアイデアをいただければ幸いです:)C#のスレッドプールにキュータスクを追加する方法

よろしくこれまで..

class RequestState 
     { 
      public WebRequest Request; 

     // holds the request 
     public object Data; 

     // store any data in this 
     public string SiteUrl; 

     // holds the UrlString to match up results (Database lookup, etc). 

     public RequestState(WebRequest request, object data, string siteUrl) 
     { 
      this.Request = request; 
      this.Data = data; 
      this.SiteUrl = siteUrl; 
     } 
    } 

    private void PROCESS_URLS_Click(object sender, EventArgs e) 
    { 
     //run the process 
     process_URLs(); 
    } 

private int ThreadsCount = 0; 

    private void process_URLs() 
    { 
     //count threads number 
     ThreadsCount = URLS_LISTVIEW.SelectedItems.Count; 

     //loop through all URLs in listview 
     for (int i = 0; i < URLS_LISTVIEW.SelectedItems.Count; i++) 
     { 
      try 
      { 
       //get url string 
       string myURLs = URLS_LISTVIEW.SelectedItems[i].SubItems[0].Text.Trim(); 

       // for each URL in the collection... 
       WebRequest request = HttpWebRequest.Create(myURLs); 
       request.Method = "GET"; 
       object data = new object(); 

       RequestState state = new RequestState(request, data, myURLs); 
       IAsyncResult result = request.BeginGetResponse(new AsyncCallback(UpdateItem), state); 
       ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(ScanTimeoutCallback), state, (30 * 1000), true); 

      } 
      catch (ThreadStateException es) 
      { 
       MessageBox.Show(es.Message); 
      } 

     } 



    } 




private void UpdateItem(IAsyncResult result) 
    { 
     RequestState state = (RequestState)result.AsyncState; 
     WebRequest request = (WebRequest)state.Request; 
     try 
     {// grab the custom state object 
      // get the Response 
      HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result); 

      // process the response... 
      Stream s = (Stream)response.GetResponseStream(); 
      StreamReader readStream = new StreamReader(s); 

      //data grabbed 
      string dataString = readStream.ReadToEnd(); 
      response.Close(); 
      s.Close(); 
      readStream.Close(); 



     //finished grabbing content for this thread. 
     ThreadsCount = ThreadsCount - 1; 


     //if all threads finished running then execute final code to tell the user the process finished 
     if (ThreadsCount < 1) 
     { 
      //show message 
      MessageBox.Show("finished"); 
     } 

     // Thread.Sleep(400); 

    } 





private static void ScanTimeoutCallback(object state, bool timedOut) 
    { 
     if (timedOut) 
     { 
      RequestState reqState = (RequestState)state; 

      if (reqState != null) 
       reqState.Request.Abort(); 


     } 
    } 

をやっているコードがあることを行うことができ、

答えて

6

は見てくださいTPLで、最大並列処理を指定するオプションがあります:私たちは私たちがを指定することができParallel.Foreach()のオーバーロードを使用するので

List<string> UriList = new List<string>(); 
... 
Parallel.ForEach(UriList, 
       new ParallelOptions() {MaxDegreeOfParallelism=10}, 
       (x) => 
{ 
    ProcessUrl(x); 
}); 

これは、並列に最大10のURLを処理します。

編集:

ここで並列に(のみ同時に10件のスレッドと最大で)http://google.com 50回HTMLをダウンロードし、アレイに結果を保存する簡単な例:

List<string> UriList = new List<string>(); 
for(int i =0;i<50;i++) 
    UriList.Add("http://google.com"); 

string[] HtmlResults = new string[UriList.Count]; 

Parallel.ForEach(UriList, 
       new ParallelOptions() { MaxDegreeOfParallelism = 10 }, 
       (url, i, j) => 
{ 
    WebClient wc = new WebClient(); 
    HtmlResults[j] = wc.DownloadString(url); 
}); 

さらに混乱を招くことはありませんが、具体的なケースではPLINQは処理するアイテム間に依存関係がなく、実際にURLが「変換」されているため、非常にうまく機能します。

var htmlResultList = UriList.AsParallel() 
          .WithDegreeOfParallelism(10) 
          .AsOrdered() 
          .Select(url => { WebClient wc = new WebClient(); return wc.DownloadString(url); }) 
          .ToList(); 
+0

これは、最初からすべてを書いておく必要があることを意味しますか? – SolidSnake

+0

あなたは 'WebRequest'などのように実際に* URLを処理するコードを再利用することができますが、個人的には' WebClient'を使ってそれを単純化します。長期的な利点を考えてみましょう - 維持するコードはずっと少なくて済みます。 – BrokenGlass

+0

サンプルを表示できますか?私はここで本当に失われています.. :( – SolidSnake

3

(これは@BrokenGlass下のコメントでなければなりませんが、私はまだコメントを投稿することができません)

あなたがしている何をするために並列処理とPLINQを使用する方法についてthis articleで見てみることができます探している。それに先行する記事全体には、良い情報もいくつかあります。

編集:これがスタンドアロンの場合は、この部分をバックグラウンドで実行する新しいスレッドを生成して、応答しないUIにならないようにします。

編集2:必要に応じて、文字列をConcurrentQueueに投げることもできます。そのため、UIから項目を探しながら追加できます。

+0

これを行うために、またはバックグラウンドワーカーを使用するために、新しいスレッドを使用する必要があるということですか?それとも両方とも同じことをするのではない.. ..? – SolidSnake

+0

@ ermac2014 - どちらでも構いません。 UIに関連付けられていない他のスレッドに作業をプッシュするだけで、ハングすることはありません。次に、作業が完了したら、いくつかのコールバックに結果をUIで更新します。 –

+0

これは意味があります:)私はさらに助けが必要かどうかをお知らせします。本当に感謝のヒントをありがとう.. – SolidSnake

関連する問題