1

我看到了很多关于 GeginGetContext 的例子,但我已经填写了所有这些都是浪费时间。也许我错了。让我们来了解一下。让我们以 .Net HttpListener主题的多线程为例:

 public class HttpListenerCallbackState
{
    private readonly HttpListener _listener;
    private readonly AutoResetEvent _listenForNextRequest;

    public HttpListenerCallbackState(HttpListener listener)
    {
        if (listener == null) throw new ArgumentNullException("listener");
        _listener = listener;
        _listenForNextRequest = new AutoResetEvent(false);
    }

    public HttpListener Listener { get { return _listener; } }
    public AutoResetEvent ListenForNextRequest { get { return _listenForNextRequest; } }
}

public class HttpRequestHandler
{
    private int requestCounter = 0;
    private ManualResetEvent stopEvent = new ManualResetEvent(false);

    public void ListenAsynchronously(IEnumerable<string> prefixes)
    {
        HttpListener listener = new HttpListener();

        foreach (string s in prefixes)
        {
            listener.Prefixes.Add(s);
        }

        listener.Start();
        HttpListenerCallbackState state = new HttpListenerCallbackState(listener);
        ThreadPool.QueueUserWorkItem(Listen, state);
    }

    public void StopListening()
    {
        stopEvent.Set();
    }


    private void Listen(object state)
    {
        HttpListenerCallbackState callbackState = (HttpListenerCallbackState)state;

        while (callbackState.Listener.IsListening)
        {
            callbackState.Listener.BeginGetContext(new AsyncCallback(ListenerCallback), callbackState);
            int n = WaitHandle.WaitAny(new WaitHandle[] { callbackState.ListenForNextRequest, stopEvent});

            if (n == 1)
            {
                // stopEvent was signalled 
                callbackState.Listener.Stop();
                break;
            }
        }
    }

    private void ListenerCallback(IAsyncResult ar)
    {
        HttpListenerCallbackState callbackState = (HttpListenerCallbackState)ar.AsyncState;
        HttpListenerContext context = null;

        int requestNumber = Interlocked.Increment(ref requestCounter);

        try
        {
            context = callbackState.Listener.EndGetContext(ar);
        }
        catch (Exception ex)
        {
            return;
        }
        finally
        {
            callbackState.ListenForNextRequest.Set();
        }

        if (context == null) return;


        HttpListenerRequest request = context.Request;

        if (request.HasEntityBody)
        {
            using (System.IO.StreamReader sr = new System.IO.StreamReader(request.InputStream, request.ContentEncoding))
            {
                string requestData = sr.ReadToEnd();

                //Stuff I do with the request happens here  
            }
        }


        try
        {
            using (HttpListenerResponse response = context.Response)
            {
                //response stuff happens here  
                string responseString = "Ok";

                byte[] buffer = Encoding.UTF8.GetBytes(responseString);
                response.ContentLength64 = buffer.LongLength;
                response.OutputStream.Write(buffer, 0, buffer.Length);
                response.Close();
            }
        }
        catch (Exception e)
        {
        }
    }
}

在这里我们可以看到这个主题的主要部分:

while (callbackState.Listener.IsListening)
        {
            callbackState.Listener.BeginGetContext(new AsyncCallback(ListenerCallback), callbackState);
            int n = WaitHandle.WaitAny(new WaitHandle[] { callbackState.ListenForNextRequest, stopEvent});
           ...
        }

我可以在 +- 所有示例中看到这种模式。我们开始获取 Contex(获取请求 = 获取请求的网络流)之后我们使用 Wait/WaitAny 方法阻塞当前线程,因此线程女巫正在获取请求什么都不做,直到它获得完整请求之后它将获得新请求. 例如,我们有带有大对象的 WCF 请求(在此请求中反序列化,并在另一端以相同的方式序列化),因此我们将等待并浪费时间,直到我们完成对该请求的全部处理。我看到它确实是同步而不是异步方式。取而代之的是,我们可以在开始获得第一个请求后立即开始获得第二个请求,而不是调用等待,而不是阻塞线程。我认为这样我们会有更好的表现。你怎么看?为什么所有的例子都包含Wait?

4

0 回答 0