Using the Asynchronous Programming Model (APM) in

2019-06-04 03:02发布

Given an operation such as this:

public void DoSomething()
{
  IWcfServiceAgentAsync agent = new WcfServiceAgentProxy();

  var request = new DoSomethingRequest();

  agent.BeginDoSomething(request,
    iar =>
    { 
      var response = agent.EndDoSomething(iar);

      /*
       * Marshal back on to UI thread with results
       */
    }, null);
}

What is really going on underneath the hood between the moment that the operation gets started, and the callback is executed? Is there a socket that's getting polled waiting for completion? Is there an underlying OS thread that gets blocked until it's return?

1条回答
ら.Afraid
2楼-- · 2019-06-04 03:22

What happens is BeginDoSomething ends up calling base.Channel.BeginGetTest(callback, asyncState); on the WCF proxy. What that proxy then does is go through each part of the "Binding Stack" you have set up for your WCF communication.

One of the main parts of the binding stack your request will pass through is the "Message Encoder". The message encoder packages your request up in to something that can be represented as a byte[] (This process is called Serializing).

Once through the message encoder your request will be sent to the Transport (be it HTTP, TCP, or something else). The transport takes the byte[] and sends it to your target endpoint, it then tells the OS "When you receive a response directed to me, call this function" via the IO Completion Ports system. (I will assume either TCP or HTTP binding for the rest of this answer) (EDIT: Note, IO Completion ports don't have to be used, it is up to the Transport layer to decide what to do, it is just most of the implementations built in to the framework will use that)

In the time between your message was sent and the response was received no threads, no poling, no nothing happens. When the network card receives a response it raises a interrupt telling the OS it has new information, that interrupt is processed and eventually the OS sees that it is a few bytes of data intended for your application. The OS then tells your application to start up a IOCP thread pool thread and passes it the few bytes of data that was received.

(See "There is no Thread" by Stephen Cleary for more info about this processes. It is talking about TPM instead of APM like in your example but the underlying layers are exactly the same.)

When the bytes from the other computer are received those bytes go back up the stack in the opposite direction. The IOCP thread runs a function from the Transport, it takes the bytes that was passed to it and hands it off to the Message Encoder. This action can happen several times!

The message encoder receives the bytes from the transport and tries to build up a message, if not enough bytes have been received yet it just queues them and waits for the next set of bytes to be passed in. Once it has enough bytes to desearalize the message it will create a new "Response" object and set it as the result of the IAsyncResult, then (I am not sure who, it may be the WCF call stack, it may be somewhere else in .NET) sees that your IAsyncResult had a callback delegate and starts up another IOCP thread and that thread is the thread your delegate is run on.

查看更多
登录 后发表回答