2011-09-08 78 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

這隻需要一個信號量,初始化爲5. WaitOne()在BeginGetResponse()調用之前,在完成回調中釋放()。 –

+0

我用一些代碼更新了這個問題。我不知道在這個例子中是否可以使用你的解決方案@HansPassant –

回答

1

你可以使用Task.Factory.FromAsync()和使用Task Scheduler that limits the Degree of Concurrency

沒有潛入FromAsync()這裏非常簡單的例子顯示,在最5個任務並行運行,不管有多少排隊:

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

看起來不錯的解決方案,但你能解釋我如何添加我的代碼來處理任務嗎? –