添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams 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();

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.

Instinctually await'ing the rest of the block actually makes sense. Is it something that makes technical sense too? – stevenrcfox Oct 20, 2011 at 10:49 @Overflow: Imagine the block is a loop, and you've got an await in the middle... when you get to the end of the block, you'll go back to before the await expression. Does that help answer your question? I'm not sure I follow... – Jon Skeet Oct 20, 2011 at 10:51

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);
                Yes, this works because of Jon's point above being 'the remainder of the execution of the method'
– stevenrcfox
                Oct 20, 2011 at 10:46
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.