жду TaskEx.Delay - PullRequest
       5

жду TaskEx.Delay

3 голосов
/ 22 апреля 2011

Я играю с HttpListener и 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)
        {
            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();
    }
}

Я ожидал следующий вывод, когда 3 клиента подключаются одновременно

Client connected 1
Client connected 2
Client connected 3
<5000ms pause>
Response 1
Response 2
Response 3

Вместо этого я получаю

Client connected 1
<5000ms pause>
Response 1
Client connected 2
<5000ms pause>
Response 2
Client connected 3
<5000ms pause>
Response 3

Если я использую продолжение, оно работает так, как я ожидал

int c = counter;
TaskEx.Delay(5000, cts.Token).ContinueWith(t => {
    Console.WriteLine("Response " + c);
    // send response
});

У меня сложилось впечатление, что await TaskEx.Delay возвращается немедленно (и перейдет к while (!cts.IsCancellationRequested)), а оставшаяся часть блока while будетбыть продолжением после 5000 мс.Так что он должен быть таким же, как мой код с .ContinueWith, нет?

Ответы [ 2 ]

5 голосов
/ 22 апреля 2011

TaskEx.Delay немедленно вернет задачу, но вы ожидаете этой задачи, прежде чем снова вызвать listener.GetContextAsyncTask(). вызывающая сторона (Start) будет продолжена, как только вы нажмете первый оператор await, который еще не завершен, но в методе Listen, он имеет появление синхронного кода - это точка из await.

Лексически это не «остаток блока», который возникает при запуске продолжения - это «остаток выполнения метода». Другими словами, метод эффективно «делает паузу» на await, но позволяет вызывающей стороне продолжить.

1 голос
/ 22 апреля 2011

Я понял, как выполнить то, что я хотел сделать (т.е. использовать await вместо .ContinueWith и делегатов):

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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...