5

I'm trying to understand the behavior of ConfigureAwait(false) within ASP.NET. Specifically if I don't await the result. An example of what I mean:

var result = DoSomethingAsync().ConfigureAwait(false);

// do some things other things here. Is our task executing simultaneously?

await result;

From what I've read, in the context of ASP.NET (not core) I understand that:

  • ConfigureAwait(false) will prevent the context from being recreated when returning to the application flow. If not specified, the context can still be restored on a different thread to the original.
  • ConfigureAwait(false) will use the default thread pool scheduler and the AspNetSynchronizationContext will no longer be involved.
  • In ASP.NET (not core), the AspNetSynchronizationContext ensures that all tasks will run sequentially (not in parallel) but each task could be run on a different thread.
  • It is undesirable to have parallel execution in the context of a single request as it affects the ASP.NET thread pool heuristics and parallelization comes in the form of handling parallel requests. Using tasks prevent threads from being blocked during IO operations.

Assuming everything I've said is correct, what happens in the above code sample? From what I've read, that piece of code would cause parallelization. If that's true, would this be considered quite dangerous with ASP.NET, stealing multiple threads per request?

If it's not true, why not? Given AspNetSynchronizationContext is no longer involved after ConfigureAwait(false) what is synchronizing the tasks?

UPDATE:

The use of the word 'sequentially' in my third point is incorrect. What I should have said is 'tasks will run one at a time'. That, to me, means not in parallel. This is taken from the information in this article. The table two thirds down describes the feature of each Sync Context. ASP.NET sync context executes one task at a time. https://msdn.microsoft.com/en-us/magazine/gg598924.aspx

Given that ConfigureAwait(false) will continue the execution away from the ASP.NET Synchronization context and onto the default context (which doesn't execute one at a time), could this potentially (but not necessarily) cause a request to use more than one thread simultaneously?

Or am I completely misunderstanding something here?

UPDATE 2:

I've asked a more concise question at:

In ASP.NET Classic can ConfigureAwait(false) cause continuations to execute in parallel on multiple threads?

Sio
  • 1,419
  • 1
  • 13
  • 23
  • The `ConfigureAwait` method has nothing to do with ASP.NET, it's part of the .net framework (both full and core). – gunr2171 Oct 03 '17 at 15:08
  • Yea, I know. I'm trying to understand what affect it has on an ASP.NET request and the AspNetSynchronizationContext. – Sio Oct 03 '17 at 15:09
  • The SynchronizationContext does not run the code in your task, it runs the code after the `await`, so a lot of your statements could be interepeted as "wrong" if the task you are talking about in them is the task returned from `DoSomethingAsync()`. – Scott Chamberlain Oct 03 '17 at 15:18
  • Sio, please explain also why standard https://stackoverflow.com/questions/13489065/best-practice-to-call-configureawait-for-all-server-side-code does not answer your question and provide some links for your bulleted statements (in particular "ensures that all tasks will run sequentially" is very strange) – Alexei Levenkov Oct 03 '17 at 16:05
  • I updated my question with more information. – Sio Oct 03 '17 at 16:29
  • I think the root of your confusion is that you believe tasks always actively *run* some code, while in reality most effective tasks simple *wait* for completion of some operation. You can wait for hundreds of operations in parallel (like https://stackoverflow.com/questions/13155052/parallel-http-requests as it normally happens with tasks), but by default you'd want to actively run code for single task... – Alexei Levenkov Oct 03 '17 at 17:06
  • I have created a more concise question at https://stackoverflow.com/questions/46565014/in-asp-net-classic-can-configureawaitfalse-cause-continuations-to-execute-in-p Hopefully it's a little clearer. – Sio Oct 04 '17 at 13:21

1 Answers1

4

The ConfigureAwait has no effect on the running of the DoSomethingAsync() function.

var result = DoSomethingAsync().ConfigureAwait(false);

// do some things other things here. Is our task executing simultaneously?

await result;

and

var result = DoSomethingAsync();

// do some things other things here. Is our task executing simultaneously?

await result.ConfigureAwait(false);

behave exactly the same. ConfigureAwait only modifies the behavior of the await statement.

Even if you had .ConfigureAwait(true) you still could be executing tasks simultaneously, the only thing that changes is how the context after the await is set up.

Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
  • So could DoSomethingAsync be waiting on an IO operation to complete and a thread be executing code up to the await, simultaneously? This suggests you could improve performance by awaiting a result only when you needed it. Also, within this code is it ever possible for more than one thread to be used simultaneously? Can a single request be occupying multiple threads at once? – Sio Oct 03 '17 at 15:24
  • You are correct, if waiting on IO it could do other work on the initial thread that called `DoWorkAsync()`. If `DoSomethingAsync()` had an `await foo.ConfigureAwait(false)` inside of it and you have not hit the `await` in your outer function yet but the inner `await` completes then you could technically have two threads doing work for the same "request", however because the sync context is gone on the inner method the new thread is not really considered part of the request anymore. – Scott Chamberlain Oct 03 '17 at 15:34
  • Would you consider this bad? Everything I've read seems to suggest one request should only ever occupy zero or one thread at a time. This is why you should avoid Task.StartNew()/Task.Run() in ASP.NET. I've never read anything suggesting I should avoid ConfigureAwait(false) though and it appears to have the same potential pitfall. – Sio Oct 03 '17 at 15:42
  • @Sio - since you presumably read something about https://www.bing.com/search?q=c%23+task+thread you should know that async code does not necessary creates new threads... Which makes your comments somewhat confusing as you seem to imply that just using `Task` in ASP.Net there instantly multiple threads involved... – Alexei Levenkov Oct 03 '17 at 15:54
  • Yea, I know Task != Thread, but two tasks can be executed on two different threads. A single thread can't execute two Tasks simultaneously. – Sio Oct 03 '17 at 16:01
  • 2
    @Sio ???? Tasks don't even need to use threads.... You can start 100 async reads and `WhenAll` them - there will be only single thread and all reads will run in parallel... Or you mean something different with "A single thread can't execute two Tasks simultaneously"? – Alexei Levenkov Oct 03 '17 at 16:09