0

この投稿を使用して、たとえば 200 個のプロキシをチェックするコードを書きました。ソケットのタイムアウトは 2 秒です。すべてが機能していますが、コード #1が 200 個のプロキシをチェックするのに 2 分以上かかるという問題は、2 秒のタイムアウトに制限されています。しかし、コード #2では 200 個のプロキシをチェックするのに 2 秒かかり、コード# 2で 1000 個のプロキシをチェックするのにも 2 秒かかります。

コード #1は ThreadPool を使用します。 コード #1はソケットを開きproxyCount、2 秒間スリープ状態になり、何が成功したかをチェックします。ちょうど2秒かかります。

では、コード #1の問題はどこにあるのでしょうか。最小 20 スレッドの ThreadPool が、スレッドなしで実行するよりもはるかに遅いのはなぜですか?

コード#1

int proxyCount = 200;  
CountdownEvent cde = new CountdownEvent(proxyCount);     
private void RefreshProxyIPs(object obj)
{     
    int workerThreads, ioThreads;
    ThreadPool.GetMinThreads(out workerThreads, out ioThreads);
    ThreadPool.SetMinThreads(20, ioThreads);

    var proxies = GetServersIPs(proxyCount);
    watch.Start();
    for (int i = 0; i < proxyCount; i++)
    {
        var proxy = proxies[i];
        ThreadPool.QueueUserWorkItem(CheckProxy, new IPEndPoint(IPAddress.Parse(proxy.IpAddress), proxy.Port));
    }
    cde.Wait();
    cde.Dispose();
    watch.Stop();
}

private List<IPEndPoint> list = new List<IPEndPoint>();
private void CheckProxy(object o)
{
     var proxy = o as IPEndPoint;
     using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
     {
         var asyncResult = socket.BeginConnect(proxy.Address, proxy.Port, null, null);
         if (asyncResult.AsyncWaitHandle.WaitOne(2000))
         {
             try
             {
                 socket.EndConnect(asyncResult);
             }
             catch (SocketException)
             {
             }
             catch (ObjectDisposedException)
             {
             }
         }
         if (socket.Connected)
         {
             list.Add(proxy);
             socket.Close();
         }
     }
     cde.Signal();
}

コード #2

int proxyCount = 200;
var sockets = new Socket[proxyCount];
var socketsResults = new IAsyncResult[proxyCount];
var proxies = GetServersIPs(proxyCount);
for (int i = 0; i < proxyCount; i++)
{
      var proxy = proxies[i];
      sockets[i] = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      socketsResults[i] = sockets[i].BeginConnect(IPAddress.Parse(proxy.IpAddress), proxy.Port, null, proxy);             
}
Thread.Sleep(2000);
for (int i = 0; i < proxyCount; i++)
{
     var success = false;
     try
     {
         if (socketsResults[i].IsCompleted)
         {
              sockets[i].EndConnect(socketsResults[i]);
              success = sockets[i].Connected;
              sockets[i].Close();
         }

         sockets[i].Dispose();
     }
     catch { }

     var proxy = socketsResults[i].AsyncState as Proxy;
     if (success) {  _validProxies.Add(proxy); }
}
4

2 に答える 2

1

開始するスレッドプール スレッドは、あまり良い tp スレッドではありません。それらは実際の作業を実行するのではなく、WaitOne() 呼び出しでブロックするだけです。そのため、そのうち 20 個がすぐに実行を開始し、2 秒間完了しません。スレッドプール スケジューラは、スレッドの 1 つが完了した場合、またはいずれのスレッドも 0.5 秒以内に完了しなかった場合にのみ、別のスレッドの開始を許可します。次に、追加の実行を許可します。そのため、すべてのリクエストが完了するまでに時間がかかります。

SetMinThreads() を呼び出して最小値を 200 に設定することで、これを修正できます。しかし、それはシステム リソースを非常に浪費します。Socket.BeginConnect() を 200 回呼び出して、2 秒後に何が起こったかを調べることもできます。あなたの高速バージョン。

于 2012-06-12T14:22:23.450 に答える
0

最初の例のように、各プロキシ接続がタイムアウトするか、2 秒のいずれか早い方を待っています。さらに、200 の個別の作業要求をキューに入れています。スレッド プールのサイズは、おそらくこれよりもずっと小さくなるでしょう。GetMaxThreadsで確認してください。その数の作業リクエストのみを同時に実行することになり、次のリクエストは前のアイテムがタイムアウトするまで待機する必要があります。

于 2012-06-12T14:24:31.147 に答える