2012-07-12 88 views
1

我正在嘗試多線程httpwebrequest。它不需要返回響應,我只需要儘快發送它們。目前我正在使用任務,但顯然這不是最有效的做事方式,因爲它使用您的系統規格來確定線程而不是連接速度。如何高效地多線程HttpWebRequests?

所以我想我想問什麼是使用基於連接速度的線程而不是您的PC的核心數量的最有效的方式。

感謝

+2

第二@Asif的回答,異步I/O可能比創建更多的線程更有效。 – 2012-07-12 17:09:29

回答

6

您可以使用BeginGetResponse()方法這是WebRequest一個async方法。

1

我建議你建立一個工作隊伍,跟蹤字典中運行的工作人員,啓動新的工作人員作爲跑完工。這可讓您調整活動工作人員的人數。它還會爲您提供一組活動工作人員,以便您需要向他們發送停止消息。

你需要添加到您的app.config讓過去的兩個默認的連接限制:

<system.net> 
<connectionManagement> 
    <remove address="*"/> 
    <add address="*" maxconnection="10" /> 
</connectionManagement> 
</system.net> 

在下面的例子中,我使用回調從隊列和刪除工作者Monitor來關閉等待工作隊列的清空。

using System; 
using System.Collections.Generic; 
using System.Threading; 

namespace Demo 
{ 
    class Program 
    { 
     static Queue<Worker> waitingWorkers = new Queue<Worker>(); 
     static Dictionary<int, Worker> activeWorkers = new Dictionary<int, Worker>(); 
     static int maxThreads = 10; 
     static object waitLock = new object(); 

     static void Main(string[] args) 
     { 
      for (int i = 0; i < 100; i++) 
      { 
       waitingWorkers.Enqueue(new Worker(new WorkerDoneDelegate(WorkerDone))); 
      } 

      lock (waitLock) 
      { 
       while (waitingWorkers.Count > 0) 
       { 
        if (activeWorkers.Count > maxThreads) 
        { 
         Monitor.Wait(waitLock); 
        } 
        Worker worker = waitingWorkers.Dequeue(); 
        Thread thread = new Thread(worker.SendSomething); 
        thread.IsBackground = true; 
        activeWorkers[thread.ManagedThreadId] = worker; 
        thread.Start(); 
       } 
      } 
      Console.WriteLine("Queue empty"); 
      Console.ReadKey(); 
     } 

     static void WorkerDone() 
     { 
      lock (waitLock) 
      { 
       activeWorkers.Remove(Thread.CurrentThread.ManagedThreadId); 
       Console.WriteLine("Worker done - id=" + Thread.CurrentThread.ManagedThreadId.ToString()); 
       Monitor.Pulse(waitLock); 
      } 
     } 

     public delegate void WorkerDoneDelegate(); 
     public class Worker 
     { 
      static Random rnd = new Random(); 

      WorkerDoneDelegate Done; 

      public Worker(WorkerDoneDelegate workerDoneArg) 
      { 
       Done = workerDoneArg; 
      } 

      public void SendSomething() 
      { 
       Console.WriteLine("Worker send - id=" + Thread.CurrentThread.ManagedThreadId.ToString()); 
       Thread.Sleep(rnd.Next(1, 1000)); 
       Done(); 
      } 
     } 
    } 
} 
0

或者乾脆使用的Parallel.For /的ForEach它會做的線程優化(選擇池大小,線程數,等等,等等。)爲您:)

2

默認情況下,.NET應用程序是允許打開2個連接到Web服務器。您可以通過使用常規的調用或異步方法,用的HttpWebRequest/HttpWebResponse設置此變量

//Set the connection limit of HTTP 
System.Net.ServicePointManager.DefaultConnectionLimit = 20; 

或者增加數量,必須妥善處置/關閉從GetReponseStream()的流。通過從GetResponseStream()關閉Stream,你的應用程序將在完成後終止HTTP連接。

例如,在下面的代碼,我從網上

public static StreamReader LoadWeb(string URL) 
    { 
     if (!URL.StartsWith("http")) 
     { 
      URL = "http://" + URL; 
     } 

     HttpWebResponse myResponse = null; 
     HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(new Uri(URL)); 

     System.IO.Stream myStream = null; 
     StreamReader myStreamReader = null; 
     myRequest.Method = "GET"; 
     myRequest.Proxy = null; 
     myRequest.Timeout = 60000; 
     myRequest.KeepAlive = false; 
     try 
     { 
      myResponse = (HttpWebResponse)myRequest.GetResponse(); 
     } 
     catch (Exception ex) 
     { 
      System.Windows.Forms.MessageBox.Show("Error : " + ex.Message); 
      return null; 
     } 

     if (myResponse != null) 
     { 
      if (myResponse.StatusCode == System.Net.HttpStatusCode.OK) 
      { 
       myStream = myResponse.GetResponseStream(); 
       myStreamReader = new StreamReader(myStream); 
      } 
     } 

     return myStreamReader; 

    } 

後返回StreamReader的,我從LoadWeb功能

StreamReader reader = LoadWeb("http://www.google.com"); 
//...process the reader 
//Finally, close the reader 
if (reader != null) 
    reader.Close(); //This line will terminate the HTTP connection 

希望它可以幫助的回報。

+0

反正這不是多線程。 – user2913184 2018-02-12 21:44:05