Does C# Async/Await work like interrupt? - c#

I tested console application like this:
class Program
{
static void Main(string[] args)
{
Test();
Console.WriteLine("C");
Console.ReadLine();
}
static async void Test()
{
Console.WriteLine("A");
await Task.Delay(2000);
Console.WriteLine("B");
}
}
This application printed A and C immmediately then B after 2 seconds. It looks fine. But I read an article about async/await "There Is No Thread" (http://blog.stephencleary.com/2013/11/there-is-no-thread.html), it says async/await does not create additional thread.
So back to my console application, I think that the main thread is blokced on Console.ReadLine(), so the remain code in Test() (Console.WriteLine("B")) is not executed until Console.ReadLine() is complete. But actual result is different, the remain code is executed regardless of the blocking of main thread.
I want to know that await works like CPU interrupt, so the instruction pointer is moved to the remain code(Console.WriteLine("B");) and moved back to interrupted position(Console.ReadLine();) after execution?

Unlike a Windows form app, console applications don't have a single "blessed" thread (the UI thread). As such, no special synchronization context is employed by default in console applications and so the continuations that await makes use of are in fact scheduled using the thread pool.
So there's no need to "interrupt" the thread that's currently waiting on Console.ReadLine - another thread is used instead.

Related

Does async method get its own thread [duplicate]

I am new to TPL and I am wondering: How does the asynchronous programming support that is new to C# 5.0 (via the new async and await keywords) relate to the creation of threads?
Specifically, does the use of async/await create a new thread each time that they are used? And if there many nested methods that use async/await, is a new thread created for each of those methods?
In short NO
From Asynchronous Programming with Async and Await : Threads
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. The method runs on the current
synchronization context and uses time on the thread only when the
method is active. You can use Task.Run to move CPU-bound work to a
background thread, but a background thread doesn't help with a process
that's just waiting for results to become available.
According to MSDN : async keyword
An async method runs synchronously until it reaches its first await expression, at which point the method is suspended until the awaited task is complete. In the meantime, control returns to the caller of the method, as the example in the next section shows.
Here is a sample code to check it :
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
private void Print(string txt)
{
string dateStr = DateTime.Now.ToString("HH:mm:ss.fff");
Console.WriteLine($"{dateStr} Thread #{Thread.CurrentThread.ManagedThreadId}\t{txt}");
}
private void Run()
{
Print("Program Start");
Experiment().Wait();
Print("Program End. Press any key to quit");
Console.Read();
}
private async Task Experiment()
{
Print("Experiment code is synchronous before await");
await Task.Delay(500);
Print("Experiment code is asynchronous after first await");
}
}
And the result :
We see the code of Experiment() method after await executes on another Thread.
But if I replace the Task.Delay by my own code (method SomethingElse) :
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
private void Print(string txt)
{
string dateStr = DateTime.Now.ToString("HH:mm:ss.fff");
Console.WriteLine($"{dateStr} Thread #{Thread.CurrentThread.ManagedThreadId}\t{txt}");
}
private void Run()
{
Print("Program Start");
Experiment().Wait();
Print("Program End. Press any key to quit");
Console.Read();
}
private async Task Experiment()
{
Print("Experiment code is synchronous before await");
await SomethingElse();
Print("Experiment code is asynchronous after first await");
}
private Task SomethingElse()
{
Print("Experiment code is asynchronous after first await");
Thread.Sleep(500);
return (Task.CompletedTask);
}
}
I notice the thread remains the same !
In conclusion, I'll say async/await code could use another thread, but only if the thread is created by another code, not by async/await.
In this case, I think Task.Delay created the thread, so I can conclude async/await does not create a new Thread like said by #Adriaan Stander.
Sorry for being late to the party.
I am new to TPL and I am wondering: How does the asynchronous
programming support that is new to C# 5.0 (via the new async and await
keywords) relate to the creation of threads?
async/await is not introduced for thread creation, but to utilize the current thread optimally.
Your app might read files, wait for response from another server or even do a computation with high memory access (Simply any IO task). These tasks are not CPU intensive (Any task that will not use 100% of your thread).
Think about the case when you are processing 1000 non CPU intensive tasks. In this case, process of creating 1000s of OS level thread might eat up more CPU and Memory than doing actual work on a single thread (4mb per thread in Windows, 4MB * 1000 = 4GB). At the same time if you run all the tasks sequentially, you might have to wait until the IO tasks gets finished. Which end up in long time to complete the task, while keeping the CPU idle.
Since we require parallelism to complete multiple tasks quickly, at the same time all parallel tasks are not CPU hungry, but creating threads is inefficient.
The compiler will break the execution at any method call to an async method (which gets called with an await) and immediately execute the code outside of the current code branch, once an await is reached, the execution will go inside the previous async. This will be repeated again and again until all the async calls are completed and their awaiters are satisfied.
If any of the async method have heavy CPU load without a call to an async method, then yes, your system will become unresponsive and all the remaining async methods will not get called until the current task is finished.
So I've been reading up on the threading model, and Async / Await can certainly lead to new threads being used (not necessarily created - the pool creates them at application start). It's up to the scheduler to determine if a new thread is needed. And as I see it, a call to an awaitable function may have internal details that increase the chances of the scheduler utilizing another thread; simply because more work means more opportunities / reasons for the scheduler to divvy out work.
WinRT async operations automatically happen on the thread pool. And typically you will be calling FROM the thread pool, except for UI thread work .. Xaml/Input/Events.
Async operations started on Xaml/UI threads have their results delivered back to the [calling] UI thread. But asynchronous operation results started from a thread pool thread are delivered wherever the completion happens, which may not be the same thread you were on before. The reason behind this is that code written for the thread pool is likely to be written to be thread safe and it is also for efficiency, Windows doesn't have to negotiate that thread switch.
So again, in answer to the OP, new threads are not necessarily created but your application can and will use multiple threads to complete asynchronous work.
I know this seems to contradict some of the literature regarding async / await, but that's because although the async / await construct is not by itself multithreaded. Awaitables are the, or one of the mechanisms by which the scheduler can divide work and construct calls across threads.
This is at the limit of my knowledge right now regarding async and threading, so I might not have it exactly right, but I do think it's important to see the relationship between awaitables and threading.
Using Async/Await doesn't necessarily cause a new thread to be created. But the use of Async/Await can lead to a new thread to be created because the awaitable function may internally spawn a new thread. And it often does, making the statement 'No, it doesn't spawn threads' almost useless in practice. For example, the following code spawns new threads.
VisualProcessor.Ctor()
{
...
BuildAsync();
}
async void BuildAsync()
{
...
TextureArray dudeTextures = await TextureArray.FromFilesAsync(…);
}
public static async Task<TextureArray> FromFilesAsync(...)
{
Debug.WriteLine("TextureArray.FromFilesAsync() T1 : Thread Id = " + GetCurrentThreadId());
List<StorageFile> files = new List<StorageFile>();
foreach (string path in paths)
{
if (path != null)
files.Add(await Package.Current.InstalledLocation.GetFileAsync(path)); // << new threads
else
files.Add(null);
}
Debug.WriteLine("TextureArray.FromFilesAsync() T2 : Thread Id = " + GetCurrentThreadId());
...
}
In case of Java Spring Framework, a method annotated with #Async runs in a separate thread. Quoting from official guide (https://spring.io/guides/gs/async-method) -
The findUser method is flagged with Spring’s #Async annotation,
indicating that it should run on a separate thread. The method’s
return type is CompletableFuture instead of User, a requirement
for any asynchronous service.
Of course in the backend it uses a Thread Pool and a Queue (where async tasks wait for a thread to be back in the pool).

If async/await doesn't create new thread then explain this code

I've read this thread which claims with reference to msdn with idea that async/await doesn't create new threads. Please look at following code:
static class Program
{
static void Main(string[] args)
{
var task = SlowThreadAsync();
for(int i = 0; i < 5; i++)
{
Console.WriteLine(i * i);
}
Console.WriteLine("Slow thread result {0}", task.Result);
Console.WriteLine("Main finished on thread {0}", Thread.CurrentThread.ManagedThreadId);
Console.ReadKey();
}
static async Task<int> SlowThreadAsync()
{
Console.WriteLine("SlowThreadAsync started on thread {0}", Thread.CurrentThread.ManagedThreadId);
await Task.Delay(2000);
Console.WriteLine("SlowThreadAsync completed on thread {0}", Thread.CurrentThread.ManagedThreadId);
return 3443;
}
}
As result of this code I got different ThreadId. Why the same thread gets different ThreadId?
You're using a console application for your example. This effects greatly the outcome of your test. A console application has no custom SynchronizationContext (like Winforms, WPF and ASP.NET have), hence it uses the ThreadPoolTaskScheduler to schedule continuations on an arbitrary thread-pool thread. Try this same example in a UI application and you'll see the continuation invoked on the same thread.
What the articles you linked are trying to get across is that calling async methods does not guarantee that any of the code runs on a separate thread. So if you do want to guarantee this, you have to do it manually. In particular they're not trying to say that an async method will always run on the same thread as the calling method, because this is blatantly false in many scenarios.
I know its been a bit since the question was asked, but I ran into this problem and have come up with more details on why/when this happens. await works by scheduling the code following the await to be run after the awaited task finishes, on whatever thread the threadpool finds convenient. Oftentimes this seems to be on the same thread as the awaited task. Not sure how this plays with SynchronizationContext mentioned in other answers.
I have noticed an exception is when the awaited task finished quickly, it seems like their isn't enough time to place the code on the callback, so the code ends up being called on a third thread.

Main Thread terminates before Task thread completion

Hi i need your help guys,
i declared new Task inside my main method like this:
static void Main(string[] args)
{
Task firstTask = Task.Factory.StartNew(()getPackage(packageId));
Task secondTask=firstTask.ContinueWith((_=>UpdatePackage(myPackage)));
}
My problem is, the main thread terminates before my task completes its action.
How should I wait Task to complete its action before terminating the main thread?
Add the following code to make your main thread block until you hit enter in the command window.
Console.Readline();
UPDATE:
If you want a non-interactive solution, then you could just wait for all the tasks to complete.
Task.WaitAll(firstTask, secondTask);
You can use an alternate paradigm for dealing with this.
static void Main(string[] args)
{
MainAsync().Wait();
}
static async Task MainAsync()
{
Task firstTask = new Task(()=>getPackage(packageId));
firstTask.ContinueWith(()=>UpdatePackage(myPackage)));
await firstTask.Run();
}
Be careful with mixing asynchronous and synchronous code like this, but, for your purposes, this should work fine (if this were winforms or WPF, you might have to worry about messaging to the UI thread, but that's not relevant here.
Assign your task to a Thread and then in your main call the .Join() function of the created thread (after it has been started of course). That way the application will wait until the task is over before ending.
This solution is more complexe than a Console.ReadLine but allows you to leave when the ask is over not before and not after.

If an async method is single threaded how can it be run in the background?

I'm trying to understand async/await and have read a number of articles but am still confused about the synchronous/asynchronous nature.
I have the following test console app:
static void Main(string[] args)
{
var test = FooAsync();
Console.WriteLine("After FooAsync");
for (int i = 0; i < 100; i++)
Console.WriteLine("After that");
Console.ReadKey();
}
private static async Task FooAsync()
{
Console.WriteLine("Before delay");
await Task.Delay(1);
Console.WriteLine("After delay");
}
The code gives output along the lines of:
Before delay
After FooAsync
After that
After that
After that
After that
After delay
After that
.
.
I understand that async/await will not create a separate thread for processing and that at the point FooAsync reaches the await Task.Delay(1) line it will return back to Main as the task will not yet have completed, however, as we are only running on a single thread can someone explain what triggers the FooAsync method to resume at some arbitrary point within Main before Main can then continue?
Update
I take it back and i3arnon and dariogriffo are correct. The code does use multiple threads (as I'd have seen before had looked in the debugger or done the obvious as kha suggested). I'd been confused by the Threads section on the following page https://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_Threads not realising that a "continuation" actually refers to a continuation task schedule to run as soon as the task being "awaited" finishes.
This isn't single threaded.
When the delay task completes the rest of the method is posted to the ThreadPool and runs concurrently with your main thread. The "trigger" here is the callback of the internal System.Threading.Timer being used inside Task.Delay.
This behaviour depends on the SynchronizationContext. In a UI environment this would have been posted to the same UI thread and would have to wait until that thread is free.
If you would have been waiting for the task returned from FooAsync then you would only have a single thread running each time.
Async/await may create new threads OR NOT, it depends of the nature of the operation.
If the operation is an IO (for example disks/network operations) probably is coded in a way it will not spin a new thread. You can read from here:
The async and await keywords don't cause additional threads to be created?
If you create your own Async operation and you create a thread, that's a different story, that's why you shouldn't do async over sync
http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx
You can check this also but using Thread.CurrentThread to get the Id of the process. (Add that to a Console.WriteLine)
It's a pretty common misconception that the async or await keywords create new threads. They don't.
The threads are created by running a Task. In this case, the thread is created by the Task.Delay call.

await Task.Run(...) behaving differently for console and windows application

I have a console application with the following code
static void Main(string[] args) {
Method();
Console.ReadKey();
}
private static void Method() {
Task t = DoSomething();
t.Wait();
Console.WriteLine("Finished");
}
private static async Task DoSomething() {
await Task.Run(() =>
Thread.Sleep(1000));
}
Everything works exactly as I expect it to and the console displays "Finished" one second after running the program. When I move the same code into a windows application then I find that the program just stops
private void button1_Click(object sender, EventArgs e) {
Task t = DoSomething();
t.Wait();
MessageBox.Show("Finished");
}
private static async Task DoSomething() {
await Task.Run(() =>
Thread.Sleep(1000));
}
The debugger shows the current line of execution is t.Wait(), even after the Task in the DoSomething method has been run.
Is there something different that I need to do in a windows application that I don't need to do in a console application? Or am I fundamentally misunderstanding something?
That's something that happens quite often. You're causing a deadlock.
To put it simply, frameworks like WinForms and WPF "enforce" a thread synchronization context, which means that whenever you launch a new task, the rest of your code will continue on the same thread as it started. This is done to ensure that, for example, code that started on the UI thread will continue running on the same thread after the task returns.
Because you're blocking on the task (with the Wait method), and the task is trying to return a value to that blocking thread, both threads go into a deadlock state.
This behaviour doesn't happen in a console application because no thread synchronization context is enforced, the continuation of a task can run on a completely different third thread.
Stephen Cleary explains this very well here: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Categories

Resources