2011-09-08 20 views
1

サーバからファイルをダウンロードするには、WebRequest.BeginGetResponseの非同期リクエストを作成します。すべての作品がいいですが、私は同時に5つのファイルをダウンロードしたいと思います。 Javaでは固定スレッドプールを使用しますが、C#で同じことをする方法はわかりません。何か案は?同時ダウンロード制限

class HttpFetcher 
{ 
    public void MakeRequest(Uri uri) 
    { 
     WebRequest request = WebRequest.Create(uri); 
     request.Proxy = null; 
     RequestState requestState = new RequestState(); 
     requestState.Request = request; 
     IAsyncResult result = (IAsyncResult) request.BeginGetResponse(new AsyncCallback(ResponseCallback), requestState); 

     ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeOutCallback), request, 1000, true); 
    } 

    private void ResponseCallback(IAsyncResult result) 
    { 
     try 
     { 
      RequestState requestState = (RequestState)result.AsyncState; 
      WebRequest request = requestState.Request; 
      requestState.Response = request.EndGetResponse(result); 
      Stream responseStream = requestState.Response.GetResponseStream(); 
      requestState.ResponseStream = responseStream; 
      IAsyncResult asynchronousResultRead = responseStream.BeginRead(requestState.BufferRead, 0, 1024, new AsyncCallback(ReadCallback), requestState); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Exception raised!"); 
      Console.WriteLine("Message : {0}", ex.Message); 
      RequestState state = (RequestState)result.AsyncState; 
      if (state.Response != null) 
       state.Response.Close(); 
     } 

    } 

    private void ReadCallback(IAsyncResult result) 
    { 
     try 
     { 
      RequestState requestState = (RequestState)result.AsyncState; 
      Stream responseStream = requestState.ResponseStream; 

      int bytesRead = responseStream.EndRead(result); 
      if (bytesRead > 0) 
      { 
       requestState.RequestData.Append(Encoding.ASCII.GetString(requestState.BufferRead, 0, bytesRead)); 
       IAsyncResult asynchronousResult = responseStream.BeginRead(requestState.BufferRead, 0, 1024, new AsyncCallback(ReadCallback), requestState); 
      } 
      else 
      { 
       Console.WriteLine("\nThe HTML page Contents are: "); 
       if (requestState.RequestData.Length > 1) 
       { 
        string sringContent; 
        sringContent = requestState.RequestData.ToString(); 
        //Console.WriteLine(sringContent); 
       } 
       Console.WriteLine("\nPress 'Enter' key to continue........"); 
       responseStream.Close(); 
      } 
     } 
     catch (WebException e) 
     { 
      Console.WriteLine("WebException raised!"); 
      Console.WriteLine("\n{0}", e.Message); 
      Console.WriteLine("\n{0}", e.Status); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Exception raised!"); 
      Console.WriteLine("Source : {0}", e.Source); 
      Console.WriteLine("Message : {0}", e.Message); 
     } 
    } 

    private void TimeOutCallback(object state, bool timedOut) 
    { 
     if (timedOut) 
     { 
      WebRequest request = (WebRequest)state; 
      if (state != null) 
      { 
       request.Abort(); 
      } 
     } 
    } 
} 
+1

完了コールバックでBeginGetResponse()コールの前にWaitOne()、Release()に初期化されたセマフォだけが必要です。 –

+0

私はいくつかのコードで質問を更新しました。この例であなたのソリューションを使用することが可能かどうかはわかりません@HansPassant –

答えて

1

あなたはTask.Factory.FromAsync()を使用するとにかかわらず、最大で5つのタスクを並列に実行されていることをキューに登録されているどのように多くを示して非常に単純化した例ここFromAsync()にダイビングしないとTask Scheduler that limits the Degree of Concurrency

を使用することができます。

public static void Main() 
{ 
    var scheduler = new LimitedConcurrencyLevelTaskScheduler(5); 
    TaskFactory factory = new TaskFactory(scheduler); 

    for (int i = 0; i < 50; i++) 
    { 
     int idx = i; 
     var newTask = factory.StartNew(() => 
      { 
       Console.WriteLine("Starting " + idx); 
       Thread.Sleep(5000); 
      }); 
    } 
    Console.ReadLine(); 
} 
+0

すてきな解決策ですが、タスクを処理するためにコードを追加する方法を教えてください。 –