1

BeginXX/EndXX ペアの呼び出しで IOCP が使用されているという記事をたくさん読みました。ただし、それらをテストしたところ、BeginExecuteReader 呼び出しでは IOCP が機能しなかったのに対し、BeginGetResponse 呼び出しでは問題なく機能したという結果が得られました。

私はこの結果に非常に混乱しています。誰でも理由を教えてもらえますか?私のテストコードに何か問題がありますか?

以下にテストを示します。

  1. BeginGetResponse でテストする

    コード:

    public static void IoThread2()
    {
      ThreadPool.SetMinThreads(5, 3);
      ThreadPool.SetMaxThreads(5, 3);
      int w; int io;
      ThreadPool.GetAvailableThreads(out w, out io);
      int cid = Thread.CurrentThread.ManagedThreadId;
      Console.WriteLine("Begin:" + w.ToString() + ";" + io.ToString() + "; id = " + cid.ToString());
      ManualResetEvent waitHandle = new ManualResetEvent(false);
      WebRequest request = HttpWebRequest.Create("http://www.cnblogs.com/");
      AsyncCallback cb = new AsyncCallback(IOThread2CallBack);
      request.BeginGetResponse(cb, request);
      waitHandle.WaitOne();
    }
    
    public static void IOThread2CallBack(IAsyncResult ar)
    {
     try
     {
         WebRequest request = (WebRequest)ar.AsyncState;
         int w2; int io2;
         ThreadPool.GetAvailableThreads(out w2, out io2);
         int cid2 = Thread.CurrentThread.ManagedThreadId;
         Console.WriteLine("End:" + w2.ToString() + ";" + io2.ToString() + "; id = " + cid2.ToString());
         var response = request.EndGetResponse(ar);
      }catch (Exception ex){ }
    }
    

    結果:

    Begin:5;3; id = 10
    End:5;2; id = 13
    

    コールバックの実行には 1 つの IO スレッドが使用されました。

  2. BeginExecuteReader コードでテストします。

    public static void IoThread1()
    {
         ThreadPool.SetMinThreads(5, 3);
         ThreadPool.SetMaxThreads(5, 3);
         int w; int io;
         ThreadPool.GetAvailableThreads(out w, out io);
         int cid = Thread.CurrentThread.ManagedThreadId;
         Console.WriteLine("Begin:" + w.ToString() + ";" + io.ToString() + "; id = " + 
                        cid.ToString());
         SqlConnection connection = new SqlConnection(connectionString);
         connection.Open();
         AsyncCallback da = new AsyncCallback(IoThreadCallBack);
         SqlCommand command = new SqlCommand(s_QueryDatabaseListScript, connection);
         IAsyncResult ir = command.BeginExecuteReader(da,                             
                              command,System.Data.CommandBehavior.CloseConnection);
         ManualResetEvent waitHandle = new ManualResetEvent(false);
         waitHandle.WaitOne();
    }
    
    public static void IoThreadCallBack(IAsyncResult ar)
    {
     int w; int io;
     ThreadPool.GetAvailableThreads(out w, out io);
     int cid = Thread.CurrentThread.ManagedThreadId;
     Console.WriteLine("End:" + w.ToString() + ";" + io.ToString() + "; id = " +  
                       cid.ToString());
     SqlCommand command = (SqlCommand)ar.AsyncState;
     StringBuilder sb = new StringBuilder();
     try
     {
           using (SqlDataReader reader = command.EndExecuteReader(ar))
           {
                while (reader.Read())
                {
                    sb.Append(reader.GetString(0)).Append("; ");
                }
           }
      }
      catch (Exception ex){ }
      finally
      {
           command.Connection.Close();  
      }
     }
    

    結果:

    Begin:5;3; id = 10
    End:4;3; id = 7
    

    コールバックの実行に別の作業スレッドが使用されました

どうしたの?

4

1 に答える 1

0

あなたの再現はとてもクリエイティブです。これは興味深いケースです。

コマンド テキスト「WAITFOR DELAY '02:00';」で 100 個の SqlCommand を開始してみてください。スレッド数が時間の経過とともにどのように変化するかを観察します (統計を出力するタイマーを開始します)。

私の推測では、消費されるスレッドは 100 よりはるかに少ない (非同期動作のこの部分が機能していることを意味する) ことがわかると思います。何らかの理由で、SqlCommand は「間違った」スレッド プール スレッドを使用していますが、これはスケーラビリティをまったく低下させない可能性があります。

于 2012-03-31T12:52:47.867 に答える