does async/await method run in the same thread as caller? - c#

I have read that async/await methods runs in the same thread as caller and I saw it in a WPF application but while testing a code in console application I see it is running in a different thread than caller.
Have I missed something?

Have I missed something?
Sort of. await doesn't know anything about threads. It causes the code after the await keyword (by default) to run in the same SynchronizationContext as the caller, if it exists.
In the case of a WPF Application, the current SynchronizationContext is setup to marshal the call back to the UI thread, which means it will end up on the UI thread. (The same is true in Windows Forms). In a Console Application, there is no SynchronizationContext, so it can't post back onto that context, which means you'll end up on a ThreadPool thread.
If you were to install a custom SynchronizationContext into SynchronizationContext.Current, the call would post there. This is not common in Console Applications, however, as it typically requires something like a "message loop" to exist to work properly.

Related

C# Reusing thread that runs the Main method in a console application [duplicate]

I have been educating myself on async / await use and I think I understood under-the-hood concept. However, most of Channel 9 tutorials, MSDN articles and Stack overflow answers on async / await use GUI-based applications (Windows Forms application) to demonstrate the power of async / await.
However, I noticed a fundamental difference in async / await use in a UI-thread based application vs. regular ThreadPool thread-based applications (e.g. ASP.NET Web Application, Console Application, etc.).
Since, in UI thread-based application, the UI thread is always available (unless the process is stopped explicitly or by Windows), so the ThreadPool thread responsible for executing the code after "await" in any async method, will guarantee to find the UI thread to post the results back (if any).
However, in a console application or ASP.NET Web application, the main thread (in a console application) or the HTTP request (in an ASP.NET web application) must be waiting (at one point of time) until all async operations are completed. So there should be .Wait() and .Result call somewhere after the Async method call, if there is nothing more to work on.
Is this understanding correct? I am not questioning the benefit of having async for I/O bound or network-bound operations (I understand how it's going to increase application scalability).
Since, in UI thread based application, the UI thread is always available (unless the process is stopped explicitly or by Windows), so the ThreadPool thread responsible for executing the code after "await" in any async method, will guarantee to find the UI thread to post the results back (if any).
This is slightly confused. There's no indication that a ThreadPool thread will be required at all.
It's up to the awaitable implementation to determine where to run the continuation, but normally the current synchronization context is used to work out where to run it:
In a console application, there is no synchronization context, so a thread pool thread is used for the continuation.
In a Windows Forms application, when you're running on the UI thread the synchronization context is one which will execute code on the UI thread... so the continuation executes there (unless you use ConfigureAwait, etc...)
In an ASP.NET application, there's a synchronization context specific to ASP.NET itself.
See Stephen Cleary's MSDN article for more details.
It's not clear what you mean by your later question about having to call Wait or Result in ASP.NET or a console app... in both scenarios it may be required, but equally it may not be. It depends on what you're doing really. Don't forget that even a console app can start its own threads and do all kinds of other things - you can write an HTTP server in a console app, for example...

Use of async/await in console or web apps

As I understand it, the async/await feature in C# splits up the segments between await calls into callback methods that run on the calling thread after each awaited method has returned on a separate worker thread. The calling thread is "free" during the waiting time. The callback must be scheduled on the calling thread through some sort of event loop.
This event loop only exists in GUI applications like Windows Forms or WPF. Freeing this loop makes sure the UI remains responsive for other user interaction during long operations.
Console apps and web apps (ASP.NET) do not have such event loops, so this callback mechanism doesn't work. But then again, they do not have an event loop because they don't need one. There is no user trying to interact with the running program at any time, expecting immediate feedback. So there's no need to free the calling thread for that. It doesn't matter how many threads the operation uses, it only returns after the last bit is done.
So what's the use of async and await in console and web apps, or any kind of non-interactive code in general, like for example Windows services? How is that different or more efficient compared to simple synchronous calls?
I'm designing an API that is used by GUI and non-interactive (service and web) programs and have a hard time understanding how it behaves in non-GUI environments.
The point with async-await is that the calling thread is always freed up when you reach the first asynchronous point (i.e. the first await of an uncompleted task).
In UI apps you have a SynchronizationContext that posts the code after the awaits to the UI thread because code that interacts with the UI must be executed by the UI thread otherwise you'll get an exception. You can control that by using ConfigureAwait(false).
In console apps (and services, etc.) there's no such need, so that code runs on some ThreadPool thread. The calling thread (which is likely to be also a ThreadPool thread) was freed up and was able to do other kinds of work in the meantime instead of blocking synchronously. So async-await improves scalability as it enables doing more work with the same amount of threads.
i3arnon's answer is (as usual) excellent.
So what's the use of async and await in console and web apps, or any kind of non-interactive code in general, like for example Windows services?
The primary benefit of async on the client side is responsiveness; the primary benefit of async on the server side is scalability.
How is that different or more efficient compared to simple synchronous calls?
Client-side responsiveness and server-side scalability are achieved by the same mechanism: freeing up the calling thread. Thus, async is all about using fewer threads. On the server side, using fewer threads allows your app to make maximum use of the existing threadpool.
As I understand it, the async/await feature in C# splits up the segments between await calls into callback methods that run on the calling thread after each awaited method has returned on a separate worker thread.
This is why I'm answering. I just can't let this one go. Every time "thread" is mentioned in this understanding, it's wrong. This part is correct: await does "split up" an async method into segments.
1) The callback methods are not run on the calling thread. Rather, await will capture a "context" and resume the method on that context. On ASP.NET apps and Console apps in particular, the context does not imply a particular thread. I explain how await captures context in detail on my async intro blog post.
2) Async APIs are not normally executed on worker threads. The entire point of async is to free up threads, so blocking thread pool threads wouldn't make sense. I explain how asynchronous I/O is almost threadless in my blog post on There Is No Thread.
Async / await has nothing to do with multi threading, to quote MSDN:
The async and await keywords don't cause additional threads to be
created. Async methods don't require multithreading because an async
method doesn't run on its own thread.
Async / await allows you to structure your code with regards to long running operations (could be CPU work or I/O work). So this is applicable to any type of program (GUI, Web Service, console etc)

What's so special about UI thread?

Let's say I have a method fooCPU that runs synchronously (it doesn't call pure async methods performing I/O, or use other threads to run its code by calling Task.Run or similar ways). That method performs some heavy calculations - it's CPU bound.
Now I call fooCPU in my program without delegating it to be executed by a worker thread. If one line of fooCPU will take long to run, no other lines will be executed until it finishes. So for example, calling it from the UI thread causes the UI thread to freeze (GUI will become unresponsive).
When I stated that async/await is an imitation of mutlithreading. The lines of two different pieces of code are executed in turns, on a single thread. If one of these lines will take long to run, no other lines will be executed until it finishes.,
I've been told that it's true for async used on the UI thread, but it's not true for all other cases (ASP.NET, async on the thread pool, console apps, etc).
Could anyone tell me what this might mean? How is UI thread different from the main thread of a console program?
I think nobody wants anyone here on this forum to continue the discussion of related topics, as they appear in the comments for instance, so it's better to ask a new question.
I recommend you read my async intro post; it explains how the async and await keywords work. Then, if you're interested in writing asynchronous code, continue with my async best practices article.
The relevant parts of the intro post:
The beginning of an async method is executed just like any other method. That is, it runs synchronously until it hits an “await” (or throws an exception).
So this is why the inner method in your console code example (without an await) was running synchronously.
Await examines that awaitable to see if it has already completed; if the awaitable has already completed, then the method just continues running (synchronously, just like a regular method).
So this is why the outer method in your console code example (that was awaiting the inner method which was synchronous) was running synchronously.
Later on, when the awaitable completes, it will execute the remainder of the async method. If you’re awaiting a built-in awaitable (such as a task), then the remainder of the async method will execute on a “context” that was captured before the “await” returned.
This "context" is SynchronizationContext.Current unless it is null, in which case it is TaskScheduler.Current. Or, the simpler version:
What exactly is that “context”?
Simple answer:
If you’re on a UI thread, then it’s a UI context.
If you’re responding to an ASP.NET request, then it’s an ASP.NET request context.
Otherwise, it’s usually a thread pool context.
Putting all of this together, you can visualize async/await as working like this: the method is split into several "chunks", with each await acting as a point where the method is split. The first chunk is always run synchronously, and at each split point it may continue either synchronously or asynchronously. If it continues asynchronously, then it will continue in a captured context (by default). UI threads provide a context that will execute the next chunk on the UI thread.
So, to answer this question, the special thing about UI threads is that they provide a SynchronizationContext that queues work back to that same UI thread.
I think nobody wants anyone here on this forum to continue the discussion of related topics, as they appear in the comments for instance, so it's better to ask a new question.
Well, Stack Overflow is specifically not intended to be a forum; it's a Question & Answer site. So it's not a place to ask for exhaustive tutorials; it's a place to come when you're stuck trying to get code working or if you don't understand something after having researched everything you can about it. This is why the comments on SO are (purposefully) restricted - they have to be short, no nice code formatting, etc. Comments on this site are intended for clarification, not as a discussion or forum thread.
It is pretty simple, a thread can do only one thing at a time. So if you send your UI thread out in the woods doing something non-UI related, say a dbase query, then all UI activity stops. No more screen updates, no response to mouse clicks and key presses. It looks and acts frozen.
You'll probably say, "well, I'll just use another thread to do the UI then". Works in a console mode, kind of. But not in a GUI app, making code thread-safe is difficult and UI is not thread-safe at all because so much code is involved. Not the kind you wrote, the kind you use with a fancy class library wrapper.
The universal solution is to invert that, do the non-UI related stuff on a worker thread and leave the UI thread to only take care of the easy UI stuff. Async/await helps you do that, what's on the right of await runs on a worker. The only way to mess that up, and it is not uncommon, is to ask the UI thread to still do too much work. Like adding a line of text to a textbox once every millisecond. That's just bad UI design, humans don't read that fast.
Given
async void Foo() {
Bar();
await Task.Yield();
Baz();
}
you're right that if Foo() gets called on the UI thread, then Bar() gets called immediately, and Baz() gets called at some later time, but still on the UI thread.
However, this is not a property of the threads themselves.
What's actually going on is that this method gets split up into something similar to
Task Foo() {
Bar();
return Task.Yield().Continue(() => {
Baz();
});
}
This is not actually correct, but the ways in which it's wrong don't matter.
The argument that gets passed to my hypothetical Continue method is code that can be invoked in some way to be determined by the task. The task may decide to execute it immediately, it may decide to execute it at some later point on the same thread, or it may decide to execute it at some later point on a different thread.
Actually, the tasks themselves don't decide, they simply pass on the delegate to a SynchronizationContext. It's this synchronisation context that determines what to do with to-be-executed code.
And that's what's different between the thread types: once you access any WinForms control from a thread, then WinForms installs a synchronisation context for that specific thread, which will schedule the to-be-executed code at some later point on the same thread.
ASP.NET, background threads, it's all different synchronisation contexts, and that's what's causing the changes in how code gets scheduled.

Is the phrase from a book "The current SynchronizationContext is a property of the current thread" correct"?

Having read the phrase "The current SynchronizationContext is a property of the current thread" correct", I am a little confused...
In a C# app code in VS2010, when I type Thread.CurrentThread. I am not finding in the drop-down list of choices given by Intellisense any context-related properties for a thread.
I know that current synchronization context can be got through "= SynchronizationContext.Current;" . But this is not quite fortunate with simultaneously executed in parallel threads, tasks, etc.
Suppose from a console or WPF (*) app I create and launch a few Windows forms in its own main UI threads as well as TPL tasks.
I undermisabovestand that each winform should have its own WindowsFormaSynchronizationContext, WPF should have its own DispatcherSynchronizationContext (subclasses of SynchronizationContext class) instances, the tasks are executed in a ThreadPool with its own synchronization context, LongRunning task orobably will be executed out of thread pool in its own synchronization context...
So, why cannot the SynchronizationContext be defined from thread(s)? All answers to "Get SynchronizationContext from a given Thread" question seem to unanmous in negating tis possibility...
And the last, but not least:
Is the phrase "The current SynchronizationContext is a property of the current thread" correct" correct?
Then, how can I get the value of this property for different particular thread instances?
(*)
Recently, I was given C# WPF app code essentially using winforms.
This is accurate. The SynchronizationContext.Current property uses the current thread's m_ExecutionContext field. Which is a private field of the Thread class, that's why you don't see it in the IntelliSense dropdown.
It is important it works that way, the default SynchronizationContext doesn't synchronize anything. Its Post() method target runs on a threadpool thread. Marshaling the target call to a specific thread is a very nontrivial thing to do. That requires help from the target thread, it needs to provide a solution to the producer-consumer problem. The generic solution is a loop that retrieves messages from a thread-safe queue. Exactly the way that the UI thread of a Winforms or a WPF app works, they "pump the message loop". Application.Run() starts that loop.
So only the UI thread of such an app can support a synchronization provider that doesn't use threadpool threads to run the Post() delegate target. Accordingly, Winforms and WPF install their own synchronization provider as soon as you create a Form or Window. And only code that runs on the UI thread will see that non-default provider from the SynchronizationContext.Current property.
The consequence is that you must initialize code that need to marshal calls back to the UI thread on the UI thread. So for example creating a BackgroundWorker must be done on the UI thread. Or a task created with TaskScheduler.FromCurrentSynchronizationContext. There can technically be more than one thread that displays UI, whatever thread the init code runs on determines where the Post() delegate target will run. Which probably explains your problem, if your init code runs on a worker thread then the Post() target runs on a threadpool thread. You can pass a reference to the Synchronization.Current object to a worker thread, as long as you obtained that reference on the UI thread.

Capturing the main thread SynchronizationContext or Dispatcher from a library

I have a C# library that would like to have the ability to Send/Post work to the "main" ui thread (if one exists).
This library may be used by:
A winforms application
A native application (with UI)
A console application (with no UI)
In the library I'd like to capture something (A SynchronizationContext, a Dispatcher, a Task Scheduler, or something else) during initialization, that will allow me to (at a later time) Send/Post work to the main thread (if the main thread has that ability--i.e. it has a message pump). For example, the library would like to put up some Winforms UI on the main thread if and only if the main application has the ability for me to get to the main thread.
Things I've tried:
A SynchronizationContext:
Capturing this works fine for a Winforms application (a WindowsFormsSynchronizationContext will be installed as the Current SynchronizationContext. This also works fine for the console app--since I can detect that the Current SynchronizationContext is null (and thus, know that I don't have the ability to send/post work to the main thread). The problem here is the native UI application: It has the ability (i.e. it has a message pump), but the Current Synchronization context is null and thus I can't differentiate it from the Console app case. If I could differentiate, then I could simply install a WindowsFormsSynchronizationContext on the main thread, and I'm good to go.
A Dispatcher: Capturing this using Current creates a new SynchronizationContext. Thus, in all situations I will get back a Dispatcher. However, for a Console app, using Dispatcher.Invoke from a background thread will hang (as expected). I could use Dispatcher.FromThread (which doesn't create a Dispatcher for the thread if one doesn't exist). But the native UI application will return a null Dispatcher using this method, and so then I'm, again, stuck not being able to distinguish the UI application from the console application.
A TaskScheduler: I could use FromCurrentSynchronizationContext. This has the same problems as the SynchronizationContext. I.e. Before calling FromCurrentSyncronizationContext, I'd have to check if the Current SynchronizationContext is null (which will be the case for the Console app and the native ui application). So, again I can't distinguish the native ui application from the console application.
I, of course, could have the user of my library specify whether or not it is a UI application when they call my Initialize method, but I was hoping to avoid that complication for the user of the library if possible.
This is not in general possible, a library that's apt to be used in threads cannot make any assumptions about which particular thread is the UI thread. You can capture Synchronization.Current but that will only work correctly if your initialization method is called from the UI thread. That's not terribly unusual to work out well, like TaskScheduler.FromCurrentSynchronizationContext() tends to work by accident, but not a guarantee. You can add a check, if Thread.CurrentThread.GetApartmentState() doesn't return STA then the odds that you are not being called from the UI thread are very high. SynchronizationContext.Current will also often be null in that case, another way to check.
The (arguably) better ways are to just not worry about it and let the client code figure it out, it won't have any trouble marshaling the callback. Or to expose a property of type SynchronizationContext so that the client code can assign it. Or add it as a constructor argument. Throw an InvalidOperationException if you are ready to Post but find out that it is still null, that's an oversight that the client programmer only makes once.
I think you should make this an option to your Initialize method (or somehow allow your caller to request UI interaction), to me that just makes more sense. I don't know the specifics but these seems to me to be a "courteous" thing to do, let your caller decide if they want you to or want to support your UI. I would take it one step further and even as the caller to supply a synchronization context. But that's my opinion.
To answer your question, there are a few "hacks" you can use to determine if you're running in a console applicaiton. This SO question has some information on that: C#/.NET: Detect whether program is being run as a service or a console application
Change the library initialization to have a SyncronizationContext parameter. If the parameter is null then the library doesn't need to do anything special, if not null Post/Send GUI updates there.
I think this is exactly what AsyncOperationManager.CreateOperation() is for.“Implementing the Event-based Asynchronous Pattern” states:
The Event-based Asynchronous Pattern provides a standardized way to package a class that has asynchronous features. If implemented with helper classes like AsyncOperationManager, your class will work correctly under any application model, including ASP.NET, Console applications, and Windows Forms applications.
It is up to the caller to decide if they want to call your API on the UI thread or not. If they do, this will capture the context and events will go through the message pump in order. In a Console application you can get the same behavior if you install a SynchronizationContext such you get for free by using AsyncContext.Run() from the Nito.AsyncEx nuget package. No need for an extra property or to have to write the conditional code yourself. If no serializing synchronization context is available, AsyncOperation.Post() will use the fake synchronization context available to Console apps which just queue the event to the threadpool instead (meaning that the posts may not execute in order). Just remember to call AsyncOperation.OperationCompleted() or AsyncOperation.PostOperationCompleted() when done.
In the library I'd like to capture something (A SynchronizationContext, a Dispatcher, a Task Scheduler, or something else) during initialization
This is exactly what AsyncOperationManager.CreateOperation() does, and in an environment-agnostic way. But you should try to pair this with a call to OperationCompleted() which maybe would be more difficult given the API you want to expose. The easiest way to use AsyncOperation would be to start an operation when your library actually starts an operation instead of during initialization. Or by having the initialization routine return an IDisposable context object handle which would signal to the consumer that they need to manage its lifetime.

Categories

Resources