开发者

await TaskEx.Delay

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);
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜