I am playing with HttpListener and Async CTP
class HttpServer : IDisposable
{
HttpListener listener;
CancellationTokenSource cts;
public void Start()
{
listener = new HttpListener();
listener.Prefixes.Add("http://+:1288/test/");
listener.Start();
cts = new CancellationTokenSource();
Listen();
}
public void Stop()
{
cts.Cancel();
}
int counter = 0;
private async void Listen()
{
while (!cts.IsCancellationRequested开发者_Python百科)
{
HttpListenerContext context = await listener.GetContextAsyncTask(); // my extension method with TaskCompletionSource and BeginGetContext
Console.WriteLine("Client connected " + ++counter);
// simulate long network i/o
await TaskEx.Delay(5000, cts.Token);
Console.WriteLine("Response " + counter);
// send response
}
listener.Close();
}
}
I expected the following output when 3 clients connect at the same time
Client connected 1
Client connected 2
Client connected 3
<5000ms pause>
Response 1
Response 2
Response 3
Instead I get
Client connected 1
<5000ms pause>
Response 1
Client connected 2
<5000ms pause>
Response 2
Client connected 3
<5000ms pause>
Response 3
If I use continuation it works like I expected
int c = counter;
TaskEx.Delay(5000, cts.Token).ContinueWith(t => {
Console.WriteLine("Response " + c);
// send response
});
I was under the impression that await TaskEx.Delay
returns immediately (and will go to while (!cts.IsCancellationRequested)
) and the remainder of the while block will be the continuation after 5000ms. So it should be the same as my code with .ContinueWith
, no?
TaskEx.Delay will return a task immediately, but you're awaiting that task before you call listener.GetContextAsyncTask()
again. The caller (Start
) will continue as soon as you hit the first await
statement which isn't already completed, but within the Listen
method, it has the appearance of synchronous code - that's the point of await
.
It's not "the remainder of the block" lexically that occurs when the continuation fires - it's "the remainder of the execution of the method". In other words, the method effectively "pauses" at the await
, but allows the caller to proceed.
I figured out how to accomplish what I wanted to do (i.e. use await
instead of .ContinueWith
and delegates):
private async void Listen()
{
while (!cts.IsCancellationRequested)
{
HttpListenerContext context = await listener.GetContextAsyncTask();
Console.WriteLine("Client connected " + ++counter);
ProcessRequest(context, counter);
}
listener.Close();
}
private async void ProcessRequest(HttpListenerContext context, int c)
{
await TaskEx.Delay(5000, cts.Token);
Console.WriteLine("Response " + c);
}
精彩评论