i saw some post regarding Async and Await usage in this site. few people are saying that Async and Await complete its job on separate background thread means spawn a new background thread and few people are saying no means Async and Await does not start any separate background thread to complete its job.
so anyone just tell me what happen in case of Async and Await when it is used.
here is one small program
class Program
{
static void Main(string[] args)
{
TestAsyncAwaitMethods();
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
}
public async static void TestAsyncAwaitMethods()
{
await LongRunningMethod();
}
public static async Task<int> LongRunningMethod()
{
Console.WriteLine("Starting Long Running method...");
await Task.Delay(5000);
Console.WriteLine("End Long Running method...");
return 1;
}
}
And the output is:
Starting Long Running method...
Press any key to exit...
End Long Running method...
The problem is that async/await is about asynchrony, not threads.
If you use Task.Run, it will indeed use a background thread (via the Thread Pool, via the Task Parallel Library).
However, for IO operations it relies on IO Completion ports to notify when the operation is complete.
The only guarantee async/await makes is that when an operation completes, it will return to your caller in the SynchronizationContext that was there when it began. In practical terms, that means it will return on the UI Thread (in a Windows application) or to a thread that can return the HTTP Response (in ASP.NET)
A simple way to understand what's going on under the hood, is to use SharpLab, if you paste your short example, you'll get how the C# compiler is rewriting your code containing async / await:
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Threading.Tasks;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
internal class Program
{
[CompilerGenerated]
private sealed class <TestAsyncAwaitMethods>d__1 : IAsyncStateMachine
{
public int <>1__state;
public AsyncVoidMethodBuilder <>t__builder;
private TaskAwaiter<int> <>u__1;
private void MoveNext()
{
int num = <>1__state;
try
{
TaskAwaiter<int> awaiter;
if (num != 0)
{
awaiter = LongRunningMethod().GetAwaiter();
if (!awaiter.IsCompleted)
{
num = (<>1__state = 0);
<>u__1 = awaiter;
<TestAsyncAwaitMethods>d__1 stateMachine = this;
<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
return;
}
}
else
{
awaiter = <>u__1;
<>u__1 = default(TaskAwaiter<int>);
num = (<>1__state = -1);
}
awaiter.GetResult();
}
catch (Exception exception)
{
<>1__state = -2;
<>t__builder.SetException(exception);
return;
}
<>1__state = -2;
<>t__builder.SetResult();
}
void IAsyncStateMachine.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
this.MoveNext();
}
[DebuggerHidden]
private void SetStateMachine(IAsyncStateMachine stateMachine)
{
}
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
this.SetStateMachine(stateMachine);
}
}
[CompilerGenerated]
private sealed class <LongRunningMethod>d__2 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder<int> <>t__builder;
private TaskAwaiter <>u__1;
private void MoveNext()
{
int num = <>1__state;
int result;
try
{
TaskAwaiter awaiter;
if (num != 0)
{
Console.WriteLine("Starting Long Running method...");
awaiter = Task.Delay(5000).GetAwaiter();
if (!awaiter.IsCompleted)
{
num = (<>1__state = 0);
<>u__1 = awaiter;
<LongRunningMethod>d__2 stateMachine = this;
<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
return;
}
}
else
{
awaiter = <>u__1;
<>u__1 = default(TaskAwaiter);
num = (<>1__state = -1);
}
awaiter.GetResult();
Console.WriteLine("End Long Running method...");
result = 1;
}
catch (Exception exception)
{
<>1__state = -2;
<>t__builder.SetException(exception);
return;
}
<>1__state = -2;
<>t__builder.SetResult(result);
}
void IAsyncStateMachine.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
this.MoveNext();
}
[DebuggerHidden]
private void SetStateMachine(IAsyncStateMachine stateMachine)
{
}
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
this.SetStateMachine(stateMachine);
}
}
private static void Main(string[] args)
{
TestAsyncAwaitMethods();
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
}
[AsyncStateMachine(typeof(<TestAsyncAwaitMethods>d__1))]
[DebuggerStepThrough]
public static void TestAsyncAwaitMethods()
{
<TestAsyncAwaitMethods>d__1 stateMachine = new <TestAsyncAwaitMethods>d__1();
stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncVoidMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
}
[AsyncStateMachine(typeof(<LongRunningMethod>d__2))]
[DebuggerStepThrough]
public static Task<int> LongRunningMethod()
{
<LongRunningMethod>d__2 stateMachine = new <LongRunningMethod>d__2();
stateMachine.<>t__builder = AsyncTaskMethodBuilder<int>.Create();
stateMachine.<>1__state = -1;
AsyncTaskMethodBuilder<int> <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
}
As pointed in many other answers on SO (like that one), the async / await rewrite the code as a state machine just like for the yield statement with a method returning either IEnumerator, IEnumerable, IEnumerator<T>, IEnumerable<T>. Except that for async methods, you can return either:
Task<TResult>, for an async method that returns a value.
Task, for an async method that performs an operation but returns no value.
void, for an event handler.
Starting with C# 7.0, any type that has an accessible GetAwaiter method. The object returned by the GetAwaiter method must implement the System.Runtime.CompilerServices.ICriticalNotifyCompletion interface.
About the last bullet you can read more about it (the fact that it's pattern based) here and there. This also involves other subtle choices that are out of the scope of your question but you can have a short explanation here about ValueTask<TResult>, IValueTaskSource<TResult>, etc.
The act of rewriting of the code is delegated to the compiler, Roslyn is basically using the AsyncRewriter class to know how to rewrite the different execution paths, branching to have an equivalent code.
In both cases where you have a valid code containing either yield or async keywords you have an initial state and depending on branching, execution path, the MoveNext() call that occurs behind the scenes will move from one state to another.
Knowing that in the case of a valid async code this kind of snippet below:
case -1:
HelperMethods.Before();
this.awaiter = AsyncMethods.MethodAsync(this.Arg0, this.Arg1).GetAwaiter();
if (!this.awaiter.IsCompleted)
{
this.State = 0;
this.Builder.AwaitUnsafeOnCompleted(ref this.awaiter, ref this);
}
break;
can roughly be translated into (see Dixin's blog for more details):
case -1: // -1 is begin.
HelperMethods.Before(); // Code before 1st await.
this.currentTaskToAwait = AsyncMethods.MethodAsync(this.Arg0, this.Arg1); // 1st task to await
// When this.currentTaskToAwait is done, run this.MoveNext() and go to case 0.
this.State = 0;
this.currentTaskToAwait.ContinueWith(_ => that.MoveNext()); // Callback
break;
Bear that in mind that if you have void as a return type of an async method you won't have much currentTaskToAwait =]
few people are saying that Async and Await complete its job on separate background thread means spawn a new background thread and few people are saying no means Async and Await does not start any separate background thread to complete its job.
Regarding your code, you can track which thread is (ie. id) used and whether it is from a pool or not:
public static class Program
{
private static void DisplayCurrentThread(string prefix)
{
Console.WriteLine($"{prefix} - Thread Id: {Thread.CurrentThread.ManagedThreadId}");
Console.WriteLine($"{prefix} - ThreadPool: {Thread.CurrentThread.IsThreadPoolThread}");
}
public static void Main(params string[] args)
{
DisplayCurrentThread("Main Pre");
TestAsyncAwaitMethods();
DisplayCurrentThread("Main Post");
Console.ReadLine();
}
private static async void TestAsyncAwaitMethods()
{
DisplayCurrentThread("TestAsyncAwaitMethods Pre");
await LongRunningMethod();
DisplayCurrentThread("TestAsyncAwaitMethods Post");
}
private static async Task<int> LongRunningMethod()
{
DisplayCurrentThread("LongRunningMethod Pre");
Console.WriteLine("Starting Long Running method...");
await Task.Delay(500);
Console.WriteLine("End Long Running method...");
DisplayCurrentThread("LongRunningMethod Post");
return 1;
}
}
Will output for example:
Main Pre - Thread Id: 1
Main Pre - ThreadPool: False
TestAsyncAwaitMethods Pre - Thread Id: 1
TestAsyncAwaitMethods Pre - ThreadPool: False
LongRunningMethod Pre - Thread Id: 1
LongRunningMethod Pre - ThreadPool: False
Starting Long Running method...
Main Post - Thread Id: 1
Main Post - ThreadPool: False
End Long Running method...
LongRunningMethod Post - Thread Id: 4
LongRunningMethod Post - ThreadPool: True
TestAsyncAwaitMethods Post - Thread Id: 4
TestAsyncAwaitMethods Post - ThreadPool: True
You can notice that that the LongRunningMethod method terminates after the Main method, it's due to the fact that you used void as a return type for asynchronous method. An async void method should only be used for event handlers and nothing else (see Async/Await - Best Practices in Asynchronous Programming)
Also, as already mentionned by i3arnon, since no context has been passed, yes the program does (re)use a thread from the thread pool to resume its execution after the async method call.
About those "contexts", I would suggest you to read that article, the article will clarify what is a context, in particular a SynchronizationContext.
Beware that I said a threadpool thread to "resume" and not to execute the async piece of code, you can find out more about this here.
async methods are usually designed to leverage whathever latency is inherent to the underlying call, usually IO, eg. writing, reading something on a disk, querying something over the network and so forth.
The purpose of truly async methods is to avoid using threads for IO stuff which can help application to scale when you have a lot more requests. Typically can handle more requests in ASP.NET WebAPI with async resources since each of them will "free" the thread of the request whenever they will hit the database or whathever async-able calls you are making in that resource.
I suggest you to read the answers of that question
Void-returning async methods have a specific purpose: to make asynchronous event handlers possible. It is possible to have an event handler that returns some actual type, but that doesn't work well with the language; invoking an event handler that returns a type is very awkward, and the notion of an event handler actually returning something doesn't make much sense.
Event handlers naturally return void, so async methods return void so that you can have an asynchronous event handler. However, some semantics of an async void method are subtly different than the semantics of an async Task or async Task method.
A way to avoid this is to leverage a C# 7.1 feature and expect a Task as a return type instead of the void:
public static class Program
{
private static void DisplayCurrentThread(string prefix)
{
Console.WriteLine($"{prefix} - Thread Id: {Thread.CurrentThread.ManagedThreadId}");
Console.WriteLine($"{prefix} - ThreadPool: {Thread.CurrentThread.IsThreadPoolThread}");
}
public static async Task Main(params string[] args)
{
DisplayCurrentThread("Main Pre");
await TestAsyncAwaitMethods();
DisplayCurrentThread("Main Post");
Console.ReadLine();
}
private static async Task TestAsyncAwaitMethods()
{
DisplayCurrentThread("TestAsyncAwaitMethods Pre");
await LongRunningMethod();
DisplayCurrentThread("TestAsyncAwaitMethods Post");
}
private static async Task<int> LongRunningMethod()
{
DisplayCurrentThread("LongRunningMethod Pre");
Console.WriteLine("Starting Long Running method...");
await Task.Delay(500);
Console.WriteLine("End Long Running method...");
DisplayCurrentThread("LongRunningMethod Post");
return 1;
}
}
You'll then get
Main Pre - Thread Id: 1
Main Pre - ThreadPool: False
TestAsyncAwaitMethods Pre - Thread Id: 1
TestAsyncAwaitMethods Pre - ThreadPool: False
LongRunningMethod Pre - Thread Id: 1
LongRunningMethod Pre - ThreadPool: False
Starting Long Running method...
End Long Running method...
LongRunningMethod Post - Thread Id: 4
LongRunningMethod Post - ThreadPool: True
TestAsyncAwaitMethods Post - Thread Id: 4
TestAsyncAwaitMethods Post - ThreadPool: True
Main Post - Thread Id: 4
Main Post - ThreadPool: True
Which looks more like what you would normally expect.
More resources about async / await:
Dixin's Blog: Understanding C# async / await (1) Compilation
Dixin's Blog: Understanding C# async / await (2) Awaitable-Awaiter Pattern
Dixin's Blog: Understanding C# async / await (3) Runtime Context
Stephen Cleary: async and await
Stephen Cleary: There is no thread
Stephen Toub: ExecutionContext vs SynchronizationContext
Both of the your statements are probably true, but are confusing.
Async-await does usually complete on a separate background thread but it doesn't mean it starts any separate background thread to complete the job.
The point of these asynchronous operations is to to not hold a thread while an asynchronous operation is being executed because true asynchronous operations do not require a thread.
The parts before that operation can be CPU bound and do require a thread and they are executed by the calling thread. The parts after that operation (which is usually called the completion) also require a thread. If there's a SynchronizationContext (like there is in UI or asp.net apps) or TaskScheduler then that part is handled by them. If there isn't any that part is scheduled on the ThreadPool to be executed by an already existing background thread.
So, in your example Task.Delay creates a Task that completes after 5 seconds. During that delay there's no need for a thread so you can use async-await.
The flow of your example is this: The main thread starts executing Main, calls TestAsyncAwaitMethods, calls LongRunningMethod, prints the first message, calls Task.Delay, registers the rest of the method as a continuation to execute after the Task.Delay completes, return to Main, print the message and waits synchronously (blocks) on Console.ReadLine.
After 5 seconds the timer in Task.Delay ends and completes the Task returned from Task.Delay. The continuation is then scheduled on the ThreadPool (since it's a console app) and a ThreadPool thread that was assigned that task prints "End Long Running method...".
In conclusion, a true asynchronous operation doesn't need a thread to be able to run, but it does need a thread after it has completed which is usually a background thread from the ThreadPool but not necessarily.
You are asking the wrong question
In effect you are asking, how does a parcel get to my doorstep? By ship or by plane?
The point is that your door step doesn't care wither the parcel was delivered by sea or air.
However the main reason for Microsoft to develop the Task/async/await framework was to take advantage of Event based programming as opposed to Thread based programming.
In general Event based programming is MUCH more efficient and faster than Thread based programming. Which is why most of the .net API uses it. Up until now, however most people avoided Event based programming because it is extremely difficult to understand (again, async/wait was put into place to make this simple).
Calling await is only possible inside methods marked as async. Once you await a function, the framework knows how to remember your current calling environment and return control to it once the awaited function completes.
You can only ever await functions that return Tasks. So all await deals with is the Task object that gets returned (and until a task is returned, the method you are awaiting is executing synchronously)
To provide you with a Task, the method you are awaiting could spawn a new thread to do it's job, it could synchronously return a completed task with a value (creating a task from a result), it can do whatever it wants. All await does is give the control back to the parent of your function until and unless the Task object you received from the awaitable method is complete. At that point it will continue the execution of your method from the await line.
Need understand two things: a) async/await use tasks(tasks use thread pool) b) async/await is NOT for parallel work.
Just compile this and look at Id's:
static void Main(string[] args)
{
Console.WriteLine("Id main thread is: {0}", Thread.CurrentThread.ManagedThreadId);
TestAsyncAwaitMethods();
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
}
public async static void TestAsyncAwaitMethods()
{
Console.WriteLine("Id thread (void - 0) is: {0}", Thread.CurrentThread.ManagedThreadId);
var _value = await LongRunningMethod();
Console.WriteLine("Id thread (void - 1) is: {0}", Thread.CurrentThread.ManagedThreadId);
}
public static async Task<int> LongRunningMethod()
{
Console.WriteLine("Id thread (int) is: {0}", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Starting Long Running method...");
await Task.Delay(1000);
Console.WriteLine("End Long Running method...");
return 1;
}
The simplest solution is,
await LongRunningMethod().wait();
It will cause the main thread to wait (non blocking) till the LongRunningMethod finishes execution.
Related
In programs utilizing async-await, my understanding is like this:
an async method that IS NOT awaited will run in the background (?) and rest of the code will continue to execute before this non-awaited method finishes
an async method that IS awaited will wait until the method finishes before moving on to the next lines of code
The application below was written by me to check if the above statements are correct.
using System;
using System.Threading.Tasks;
namespace ConsoleApp3
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
DoJob();
var z = 3;
Console.ReadLine();
}
static async Task DoJob()
{
var work1 = new WorkClass();
var work2 = new WorkClass();
while (true)
{
await work1.DoWork(500);
await work2.DoWork(1500);
}
}
}
public class WorkClass
{
public async Task DoWork(int delayMs)
{
var x = 1;
await Task.Delay(delayMs);
var y = 2;
}
}
}
Here are some of my observations:
The DoJob(); call is not awaited. However, the debugger shows me that the code inside of DoJob is being executed, just as if it was a normal non-async method.
When code execution gets to await work1.DoWork(500);, I would think "OK, so maybe now the DoJob method will be left and var z = 3; will be executed? After all, 'await' should leave the method." In reality, it just goes into DoWork and doesn't leave DoJob - var z = 3; is still not executed.
Finally, when execution reaches await Task.Delay(delayMs);, DoJob is left, and the var z = 3; is reached. After that, code after the Delay is executed.
The things that I don't understand:
Why does await Task.Delay(delayMs); leave the DoJob method, but await work1.DoWork(500); does not?
I see that DoJob is executing normally. I thought it would be done in the background (maybe by one of the thread pool threads?). Looks like it could block the thread if it was some long-running method, am I right?
Why does await Task.Delay(delayMs); leave the DoJob method, but await work1.DoWork(500); does not?
Because this code:
await work1.DoWork(500);
is the same as this code:
var task = work1.DoWork(500);
await task;
So your code is calling the method first, and then awaiting the returned task. It's common to talk about await as "awaiting method calls", but that's not what actually happens - technically, the method call is done first (synchronously), and then the returned task is awaited.
I see that DoJob is executing normally. I thought it would be done in the background (maybe by one of the thread pool threads?).
No; with true asynchronous operations, there is no thread that is blocked on that operation.
Looks like it could block the thread if it was some long-running method, am I right?
Yes.
my understanding is like this
I recommend reading my async intro for a better mental framework. In summary:
async enables the await keyword. It also generates a state machine that handles creating the Task return value and stuff like that.
await operates on an "awaitable" (usually a task). First, it checks to see if it's already complete; if it is, the async method continues executing synchronously.
If the awaitable is not already complete, then await (by default) captures its context and schedules the continuation of the async method to run on that context when the awaitable completes.
The compiler splits the code in an async method in chunks. 1 before the first await and 1 between each await and 1 after the last await.
The execution will return to the caller at the first non completed awaiter or the end of the method.
This method will only return a completed Task after fully executed:
async Task M1() => await Task.CompletedTask;
This method will only return an incomplete Task that will complete when the Task returned by Task.Dealy(1000) is completed:
async Task M2() => await Task.Delay(1000);
Here's a small example:
static async Task Main(string[] args)
{
var t = TwoAwaits();
Console.WriteLine("Execution returned to main");
await t;
}
private static async Task TwoAwaits()
{
Console.WriteLine("Before awaits");
await Task.CompletedTask;
Console.WriteLine("Between awaits #1");
await Task.Delay(1000);
Console.WriteLine("Between awaits #2");
await Task.Delay(1000);
Console.WriteLine("After awaits");
}
/*
Before awaits
Between awaits #1
Execution returned to main
Between awaits #2
After awaits
*/
Let's look at the four possibilities:
(1)
void Main()
{
Console.WriteLine($"Main 0 - {Thread.CurrentThread.ManagedThreadId}");
DoJob();
Console.WriteLine($"Main 1 - {Thread.CurrentThread.ManagedThreadId}");
}
public static async Task DoJob()
{
Console.WriteLine($"DoJob 0 - {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(2000);
Console.WriteLine($"DoJob 1 - {Thread.CurrentThread.ManagedThreadId}");
}
This outputs:
Main 0 - 14
DoJob 0 - 14
DoJob 1 - 14
Main 1 - 14
It has a 2 second pause after DoJob 0.
(2)
async Task Main()
{
Console.WriteLine($"Main 0 - {Thread.CurrentThread.ManagedThreadId}");
await DoJob();
Console.WriteLine($"Main 1 - {Thread.CurrentThread.ManagedThreadId}");
}
public static async Task DoJob()
{
Console.WriteLine($"DoJob 0 - {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(2000);
Console.WriteLine($"DoJob 1 - {Thread.CurrentThread.ManagedThreadId}");
}
Again this outputs:
Main 0 - 14
DoJob 0 - 14
DoJob 1 - 14
Main 1 - 14
(3)
async Task Main()
{
Console.WriteLine($"Main 0 - {Thread.CurrentThread.ManagedThreadId}");
await DoJob();
Console.WriteLine($"Main 1 - {Thread.CurrentThread.ManagedThreadId}");
}
public static Task DoJob()
{
return Task.Run(() =>
{
Console.WriteLine($"DoJob 0 - {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(2000);
Console.WriteLine($"DoJob 1 - {Thread.CurrentThread.ManagedThreadId}");
});
}
This has different output because it has changed thread:
Main 0 - 15
DoJob 0 - 13
DoJob 1 - 13
Main 1 - 13
And finally:
async Task Main()
{
Console.WriteLine($"Main 0 - {Thread.CurrentThread.ManagedThreadId}");
DoJob();
Console.WriteLine($"Main 1 - {Thread.CurrentThread.ManagedThreadId}");
}
public static Task DoJob()
{
return Task.Run(() =>
{
Console.WriteLine($"DoJob 0 - {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(2000);
Console.WriteLine($"DoJob 1 - {Thread.CurrentThread.ManagedThreadId}");
});
}
This has a different output again:
Main 0 - 13
Main 1 - 13
DoJob 0 - 12
DoJob 1 - 12
In this last case it is not waiting for DoJob because DoJob is running on a different thread.
So if you follow the logic here the issue is that async/await doesn't create (or use) a different thread. The method called must do that.
Before Async & Await, there was two type of methods. Those who returned the result directly, and those who received a callback function as a parameter. On the latter, the method was invoked in the same thread syncronously and returned no value, and later, on the same or different thread your callback function would have been called with the result. Historically all I/O (disk, network, even memory) worked with callbacks (actually: interrupts) but medium to high level languages like C# would mask all that internally so end users don't need to learn/write low level code.
This worked pretty well up to a point, except this optimization wasted some physical resources. For example Node.js outperformed several other languages/server platforms by their limitation that forces the developers to use the callback model instead of the 'managed' mode.
This pushed C# and other languages to go back to the callback model, but the code readability really suffered (code callback spaguetti). So Async and Await was introduced.
Async and await let's you write in the 'callback model' with 'managed' syntax. All callbacks are handled by the compiler.
Each time you write 'await' in an async method, your method is actually split into two methods connected by a callback.
Now, you can write an async method that does regular sync code, without awaits, nor thread switch or I/O. That 'async' method will actually run synchronously. So, it is actually the same to await method1() or call without await. Why? because your async call is not awaiting anything, so your async code is still one piece of continous code.
If inside your method you await one, two or more different methods, then your method will be split into one, two or more pieces. And only the first piece will be guaranteed to be run synchronously. All the other pieces will run on other thread depending on the code that you are awaiting.
TL;DR;
Async/Await method is does not guarantees multi-threading or parallel processing. That will actually depend on the payload (the called async method). For example, http downloads will tipically be paralellized if you manage your awaits because those are functions that are mostly waiters of an external response. On the other side, heavy CPU processing, like compressing a file, will require other form of cpu/thread management not provided by async/await.
If you do not await an async method, your code will surely run synchronously up to the first await of the called method, given it has one. But later on, it may or not run sync.
why does await Task.Delay(delayMs); leave the DoJob method, but await work1.DoWork(500); does not?
Because, up and until there is an actual asynchronous call, it's still in the same context. If DoWork was just:
public async Task DoWork(int delayMs)
{
var x = 1;
var y = 2;
return Task.CompletedTask;
}
there would be no need for a continuation and hence, you would debug all the way without "jumping" back to the orignal await call.
Here is how your application could be remodeled if you were forced to avoid async/await for some reason. See how complex it gets to replicate the logic inside the loop. Async/await is really a gift from the heavens!
using System;
using System.Threading.Tasks;
namespace ConsoleApp3
{
class Program
{
static Task Main(string[] args)
{
Console.WriteLine("Hello World!");
DoJob();
var z = 3;
Console.ReadLine();
return Task.CompletedTask;
}
static Task DoJob()
{
var work1 = new WorkClass();
var work2 = new WorkClass();
var tcs = new TaskCompletionSource<bool>();
Loop();
return tcs.Task;
void Loop()
{
work1.DoWork(500).ContinueWith(t1 =>
{
if (t1.IsFaulted) { tcs.SetException(t1.Exception); return; }
work2.DoWork(1500).ContinueWith(t2 =>
{
if (t2.IsFaulted) { tcs.SetException(t2.Exception); return; }
if (true) { Loop(); } else { tcs.SetResult(true); }
// The 'if (true)' corresponds to the 'while (true)'
// of the original code.
});
});
}
}
}
public class WorkClass
{
public Task DoWork(int delayMs)
{
var x = 1;
int y;
return Task.Delay(delayMs).ContinueWith(t =>
{
if (t.IsFaulted) throw t.Exception;
y = 2;
});
}
}
}
Can anybody explain why this code simply hits a dead end after the WhenAll fires?
Main code:
class AsyncTests
{
public async void Start()
{
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - starting whole process, calling await DoWork1()");
await Task.WhenAll(DoWork1(), DoWork2());
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - finished awaiting DoWork1 and DoWork2");
}
public async Task DoWork1()
{
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - starting DoWork1");
await DoNothing();
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - finished DoWork1");
}
public async Task DoWork2()
{
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - starting DoWork2");
await DoNothing();
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - finished DoWork2");
}
public Task DoNothing() { return new Task(() => { /* do nothing */ }); }
}
The program control code:
static void Main(string[] args)
{
var x = new AsyncTests();
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - Main ... calling Start()");
Task.Run(() => x.Start());
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - Main ... start is running");
Console.ReadKey();
}
The output:
Thread:1 - Main ... calling Start()
Thread:1 - Main ... start is running
Thread:4 - starting whole process, calling await DoWork1()
Thread:4 - starting DoWork1
Thread:4 - starting DoWork2
UPDATE
To make this a little clearer, let's change it so that DoNothing actually calls Thread.Sleep(2000) and my objective is to run two thread sleeps simultaneously and want to use the async/await pattern to achieve this.
If I change "DoNothing" to be an async Task which performs a sleep, then I get told I need await operators in there. Which means I'd need to write yet another async method to be awaited. So what is the best way to end that chain of calls in terms of operators?
Can somebody show a best practise example of how to achieve the above?
You never start your task in DoNothing.
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task?view=netframework-4.8#remarks
Separating task creation and execution
The Task class also provides constructors that initialize the task but that do not schedule it for execution. For performance reasons, the Task.Run or TaskFactory.StartNew method is the preferred mechanism for creating and scheduling computational tasks, but for scenarios where creation and scheduling must be separated, you can use the constructors and then call the Task.Start method to schedule the task for execution at a later time.
Instead of creating a task to return, let the language do it for you.
public async Task DoNothing() { }
The above actually does nothing and will return a Task that is in its completed state and can be awaited.
The way you are currently doing it, the Task is created but it is never started or set to Completed, so awaiting it will lock up the program forever.
Just to supplement the answers and comments already given, I wanted to show a code example working the way I intended in the test. It shows the execution flow + for info, the managed thread Id of execution at specific times.
The main code:
class AsyncTests
{
public async Task StartAsync()
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Thread:{Thread.CurrentThread.ManagedThreadId} - starting whole process, calling await DoWork1Async()");
await Task.WhenAll(DoWork1Async(), DoWork2Async());
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Thread:{Thread.CurrentThread.ManagedThreadId} - finished awaiting DoWork1Async and DoWork2Async");
}
public async Task DoWork1Async()
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Thread:{Thread.CurrentThread.ManagedThreadId} - starting DoWork1Async");
await Sleep();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Thread:{Thread.CurrentThread.ManagedThreadId} - finished DoWork1Async");
}
public async Task DoWork2Async()
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Thread:{Thread.CurrentThread.ManagedThreadId} - starting DoWork2Async");
await Sleep();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Thread:{Thread.CurrentThread.ManagedThreadId} - finished DoWork2Async");
}
public async Task Sleep()
{
await Task.Delay(2000);
}
}
The calling code (note that to make this run asynchronously I had to leave out the await operator which raises the warning consider applying the 'await' operator on the StartAsync() method call.
static void Main(string[] args)
{
var x = new AsyncTests();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - {Thread.CurrentThread.ManagedThreadId} - Main ... calling Start()");
x.StartAsync();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - {Thread.CurrentThread.ManagedThreadId} - Main ... start is running");
Console.ReadKey();
}
Finally, the output - which is as expected showing the code execution/control returning to the places expected for a truly asynchronous operation. As expected two different pool threads were used to run the sleep.
10:43:36.515 - 1 - Main ... calling Start()
10:43:36.546 - Thread:1 - starting whole process, calling await DoWork1Async()
10:43:36.547 - Thread:1 - starting DoWork1Async
10:43:36.561 - Thread:1 - starting DoWork2Async
10:43:36.562 - 1 - Main ... start is running
10:43:38.581 - Thread:4 - finished DoWork2Async
10:43:38.582 - Thread:5 - finished DoWork1Async
10:43:38.582 - Thread:5 - finished awaiting DoWork1Async and DoWork2Async
Given the following code...
static void DoSomething(int id) {
Thread.Sleep(50);
Console.WriteLine(#"DidSomething({0})", id);
}
I know I can convert this to an async task as follows...
static async Task DoSomethingAsync(int id) {
await Task.Delay(50);
Console.WriteLine(#"DidSomethingAsync({0})", id);
}
And that by doing so if I am calling multiple times (Task.WhenAll) everything will be faster and more efficient than perhaps using Parallel.Foreach or even calling from within a loop.
But for a minute, lets pretend that Task.Delay() does not exist and I actually have to use Thread.Sleep(); I know in reality this is not the case, but this is concept code and where the Delay/Sleep is would normally be an IO operation where there is no async option (such as early EF).
I have tried the following...
static async Task DoSomethingAsync2(int id) {
await Task.Run(() => {
Thread.Sleep(50);
Console.WriteLine(#"DidSomethingAsync({0})", id);
});
}
But, though it runs without error, according to Lucien Wischik this is in fact bad practice as it is merely spinning up threads from the pool to complete each task (it is also slower using the following console application - if you swap between DoSomethingAsync and DoSomethingAsync2 call you can see a significant difference in the time that it takes to complete)...
static void Main(string[] args) {
MainAsync(args).Wait();
}
static async Task MainAsync(String[] args) {
List<Task> tasks = new List<Task>();
for (int i = 1; i <= 1000; i++)
tasks.Add(DoSomethingAsync2(i)); // Can replace with any version
await Task.WhenAll(tasks);
}
I then tried the following...
static async Task DoSomethingAsync3(int id) {
await new Task(() => {
Thread.Sleep(50);
Console.WriteLine(#"DidSomethingAsync({0})", id);
});
}
Transplanting this in place of the original DoSomethingAsync, the test never completes and nothing is shown on screen!
I have also tried multiple other variations that either do not compile or do not complete!
So, given the constraint that you cannot call any existing asynchronous methods and must complete both the Thread.Sleep and the Console.WriteLine in an asynchronous task, how do you do it in a manner that is as efficient as the original code?
The objective here for those of you who are interested is to give me a better understanding of how to create my own async methods where I am not calling anybody elses. Despite many searches, this seems to be the one area where examples are really lacking - whilst there are many thousands of examples of calling async methods that call other async methods in turn I cannot find any that convert an existing void method to an async task where there is no call to a further async task other than those that use the Task.Run(() => {} ) method.
There are two kinds of tasks: those that execute code (e.g., Task.Run and friends), and those that respond to some external event (e.g., TaskCompletionSource<T> and friends).
What you're looking for is TaskCompletionSource<T>. There are various "shorthand" forms for common situations so you don't always have to use TaskCompletionSource<T> directly. For example, Task.FromResult or TaskFactory.FromAsync. FromAsync is most commonly used if you have an existing *Begin/*End implementation of your I/O; otherwise, you can use TaskCompletionSource<T> directly.
For more information, see the "I/O-bound Tasks" section of Implementing the Task-based Asynchronous Pattern.
The Task constructor is (unfortunately) a holdover from Task-based parallelism, and should not be used in asynchronous code. It can only be used to create a code-based task, not an external event task.
So, given the constraint that you cannot call any existing asynchronous methods and must complete both the Thread.Sleep and the Console.WriteLine in an asynchronous task, how do you do it in a manner that is as efficient as the original code?
I would use a timer of some kind and have it complete a TaskCompletionSource<T> when the timer fires. I'm almost positive that's what the actual Task.Delay implementation does anyway.
So, given the constraint that you cannot call any existing
asynchronous methods and must complete both the Thread.Sleep and the
Console.WriteLine in an asynchronous task, how do you do it in a
manner that is as efficient as the original code?
IMO, this is a very synthetic constraint that you really need to stick with Thread.Sleep. Under this constraint, you still can slightly improve your Thread.Sleep-based code. Instead of this:
static async Task DoSomethingAsync2(int id) {
await Task.Run(() => {
Thread.Sleep(50);
Console.WriteLine(#"DidSomethingAsync({0})", id);
});
}
You could do this:
static Task DoSomethingAsync2(int id) {
return Task.Run(() => {
Thread.Sleep(50);
Console.WriteLine(#"DidSomethingAsync({0})", id);
});
}
This way, you'd avoid an overhead of the compiler-generated state machine class. There is a subtle difference between these two code fragments, in how exceptions are propagated.
Anyhow, this is not where the bottleneck of the slowdown is.
(it is also slower using the following console application - if you
swap between DoSomethingAsync and DoSomethingAsync2 call you can see a
significant difference in the time that it takes to complete)
Let's look one more time at your main loop code:
static async Task MainAsync(String[] args) {
List<Task> tasks = new List<Task>();
for (int i = 1; i <= 1000; i++)
tasks.Add(DoSomethingAsync2(i)); // Can replace with any version
await Task.WhenAll(tasks);
}
Technically, it requests 1000 tasks to be run in parallel, each supposedly to run on its own thread. In an ideal universe, you'd expect to execute Thread.Sleep(50) 1000 times in parallel and complete the whole thing in about 50ms.
However, this request is never satisfied by the TPL's default task scheduler, for a good reason: thread is a precious and expensive resource. Moreover, the actual number of concurrent operations is limited to the number of CPUs/cores. So in reality, with the default size of ThreadPool, I'm getting 21 pool threads (at peak) serving this operation in parallel. That is why DoSomethingAsync2 / Thread.Sleep takes so much longer than DoSomethingAsync / Task.Delay. DoSomethingAsync doesn't block a pool thread, it only requests one upon the completion of the time-out. Thus, more DoSomethingAsync tasks can actually run in parallel, than DoSomethingAsync2 those.
The test (a console app):
// https://stackoverflow.com/q/21800450/1768303
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace Console_21800450
{
public class Program
{
static async Task DoSomethingAsync(int id)
{
await Task.Delay(50);
UpdateMaxThreads();
Console.WriteLine(#"DidSomethingAsync({0})", id);
}
static async Task DoSomethingAsync2(int id)
{
await Task.Run(() =>
{
Thread.Sleep(50);
UpdateMaxThreads();
Console.WriteLine(#"DidSomethingAsync2({0})", id);
});
}
static async Task MainAsync(Func<int, Task> tester)
{
List<Task> tasks = new List<Task>();
for (int i = 1; i <= 1000; i++)
tasks.Add(tester(i)); // Can replace with any version
await Task.WhenAll(tasks);
}
volatile static int s_maxThreads = 0;
static void UpdateMaxThreads()
{
var threads = Process.GetCurrentProcess().Threads.Count;
// not using locks for simplicity
if (s_maxThreads < threads)
s_maxThreads = threads;
}
static void TestAsync(Func<int, Task> tester)
{
s_maxThreads = 0;
var stopwatch = new Stopwatch();
stopwatch.Start();
MainAsync(tester).Wait();
Console.WriteLine(
"time, ms: " + stopwatch.ElapsedMilliseconds +
", threads at peak: " + s_maxThreads);
}
static void Main()
{
Console.WriteLine("Press enter to test with Task.Delay ...");
Console.ReadLine();
TestAsync(DoSomethingAsync);
Console.ReadLine();
Console.WriteLine("Press enter to test with Thread.Sleep ...");
Console.ReadLine();
TestAsync(DoSomethingAsync2);
Console.ReadLine();
}
}
}
Output:
Press enter to test with Task.Delay ...
...
time, ms: 1077, threads at peak: 13
Press enter to test with Thread.Sleep ...
...
time, ms: 8684, threads at peak: 21
Is it possible to improve the timing figure for the Thread.Sleep-based DoSomethingAsync2? The only way I can think of is to use TaskCreationOptions.LongRunning with Task.Factory.StartNew:
You should think twice before doing this in any real-life application:
static async Task DoSomethingAsync2(int id)
{
await Task.Factory.StartNew(() =>
{
Thread.Sleep(50);
UpdateMaxThreads();
Console.WriteLine(#"DidSomethingAsync2({0})", id);
}, TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);
}
// ...
static void Main()
{
Console.WriteLine("Press enter to test with Task.Delay ...");
Console.ReadLine();
TestAsync(DoSomethingAsync);
Console.ReadLine();
Console.WriteLine("Press enter to test with Thread.Sleep ...");
Console.ReadLine();
TestAsync(DoSomethingAsync2);
Console.ReadLine();
}
Output:
Press enter to test with Thread.Sleep ...
...
time, ms: 3600, threads at peak: 163
The timing gets better, but the price for this is high. This code asks the task scheduler to create a new thread for each new task. Do not expect this thread to come from the pool:
Task.Factory.StartNew(() =>
{
Thread.Sleep(1000);
Console.WriteLine("Thread pool: " +
Thread.CurrentThread.IsThreadPoolThread); // false!
}, TaskCreationOptions.LongRunning).Wait();
I've discovered that TaskCompletionSource.SetResult(); invokes the code awaiting the task before returning. In my case that result in a deadlock.
This is a simplified version that is started in an ordinary Thread
void ReceiverRun()
while (true)
{
var msg = ReadNextMessage();
TaskCompletionSource<Response> task = requests[msg.RequestID];
if(msg.Error == null)
task.SetResult(msg);
else
task.SetException(new Exception(msg.Error));
}
}
The "async" part of the code looks something like this.
await SendAwaitResponse("first message");
SendAwaitResponse("second message").Wait();
The Wait is actually nested inside non-async calls.
The SendAwaitResponse(simplified)
public static Task<Response> SendAwaitResponse(string msg)
{
var t = new TaskCompletionSource<Response>();
requests.Add(GetID(msg), t);
stream.Write(msg);
return t.Task;
}
My assumption was that the second SendAwaitResponse would execute in a ThreadPool thread but it continues in the thread created for ReceiverRun.
Is there anyway to set the result of a task without continuing its awaited code?
The application is a console application.
I've discovered that TaskCompletionSource.SetResult(); invokes the code awaiting the task before returning. In my case that result in a deadlock.
Yes, I have a blog post documenting this (AFAIK it's not documented on MSDN). The deadlock happens because of two things:
There's a mixture of async and blocking code (i.e., an async method is calling Wait).
Task continuations are scheduled using TaskContinuationOptions.ExecuteSynchronously.
I recommend starting with the simplest possible solution: removing the first thing (1). I.e., don't mix async and Wait calls:
await SendAwaitResponse("first message");
SendAwaitResponse("second message").Wait();
Instead, use await consistently:
await SendAwaitResponse("first message");
await SendAwaitResponse("second message");
If you need to, you can Wait at an alternative point further up the call stack (not in an async method).
That's my most-recommended solution. However, if you want to try removing the second thing (2), you can do a couple of tricks: either wrap the SetResult in a Task.Run to force it onto a separate thread (my AsyncEx library has *WithBackgroundContinuations extension methods that do exactly this), or give your thread an actual context (such as my AsyncContext type) and specify ConfigureAwait(false), which will cause the continuation to ignore the ExecuteSynchronously flag.
But those solutions are much more complex than just separating the async and blocking code.
As a side note, take a look at TPL Dataflow; it sounds like you may find it useful.
As your app is a console app, it runs on the default synchronization context, where the await continuation callback will be called on the same thread the awaiting task has become completed on. If you want to switch threads after await SendAwaitResponse, you can do so with await Task.Yield():
await SendAwaitResponse("first message");
await Task.Yield();
// will be continued on a pool thread
// ...
SendAwaitResponse("second message").Wait(); // so no deadlock
You could further improve this by storing Thread.CurrentThread.ManagedThreadId inside Task.Result and comparing it to the current thread's id after the await. If you're still on the same thread, do await Task.Yield().
While I understand that SendAwaitResponse is a simplified version of your actual code, it's still completely synchronous inside (the way you showed it in your question). Why would you expect any thread switch in there?
Anyway, you probably should redesign your logic the way it doesn't make assumptions about what thread you are currently on. Avoid mixing await and Task.Wait() and make all of your code asynchronous. Usually, it's possible to stick with just one Wait() somewhere on the top level (e.g. inside Main).
[EDITED] Calling task.SetResult(msg) from ReceiverRun actually transfers the control flow to the point where you await on the task - without a thread switch, because of the default synchronization context's behavior. So, your code which does the actual message processing is taking over the ReceiverRun thread. Eventually, SendAwaitResponse("second message").Wait() is called on the same thread, causing the deadlock.
Below is a console app code, modeled after your sample. It uses await Task.Yield() inside ProcessAsync to schedule the continuation on a separate thread, so the control flow returns to ReceiverRun and there's no deadlock.
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
class Worker
{
public struct Response
{
public string message;
public int threadId;
}
CancellationToken _token;
readonly ConcurrentQueue<string> _messages = new ConcurrentQueue<string>();
readonly ConcurrentDictionary<string, TaskCompletionSource<Response>> _requests = new ConcurrentDictionary<string, TaskCompletionSource<Response>>();
public Worker(CancellationToken token)
{
_token = token;
}
string ReadNextMessage()
{
// using Thread.Sleep(100) for test purposes here,
// should be using ManualResetEvent (or similar synchronization primitive),
// depending on how messages arrive
string message;
while (!_messages.TryDequeue(out message))
{
Thread.Sleep(100);
_token.ThrowIfCancellationRequested();
}
return message;
}
public void ReceiverRun()
{
LogThread("Enter ReceiverRun");
while (true)
{
var msg = ReadNextMessage();
LogThread("ReadNextMessage: " + msg);
var tcs = _requests[msg];
tcs.SetResult(new Response { message = msg, threadId = Thread.CurrentThread.ManagedThreadId });
_token.ThrowIfCancellationRequested(); // this is how we terminate the loop
}
}
Task<Response> SendAwaitResponse(string msg)
{
LogThread("SendAwaitResponse: " + msg);
var tcs = new TaskCompletionSource<Response>();
_requests.TryAdd(msg, tcs);
_messages.Enqueue(msg);
return tcs.Task;
}
public async Task ProcessAsync()
{
LogThread("Enter Worker.ProcessAsync");
var task1 = SendAwaitResponse("first message");
await task1;
LogThread("result1: " + task1.Result.message);
// avoid deadlock for task2.Wait() with Task.Yield()
// comment this out and task2.Wait() will dead-lock
if (task1.Result.threadId == Thread.CurrentThread.ManagedThreadId)
await Task.Yield();
var task2 = SendAwaitResponse("second message");
task2.Wait();
LogThread("result2: " + task2.Result.message);
var task3 = SendAwaitResponse("third message");
// still on the same thread as with result 2, no deadlock for task3.Wait()
task3.Wait();
LogThread("result3: " + task3.Result.message);
var task4 = SendAwaitResponse("fourth message");
await task4;
LogThread("result4: " + task4.Result.message);
// avoid deadlock for task5.Wait() with Task.Yield()
// comment this out and task5.Wait() will dead-lock
if (task4.Result.threadId == Thread.CurrentThread.ManagedThreadId)
await Task.Yield();
var task5 = SendAwaitResponse("fifth message");
task5.Wait();
LogThread("result5: " + task5.Result.message);
LogThread("Leave Worker.ProcessAsync");
}
public static void LogThread(string message)
{
Console.WriteLine("{0}, thread: {1}", message, Thread.CurrentThread.ManagedThreadId);
}
}
static void Main(string[] args)
{
Worker.LogThread("Enter Main");
var cts = new CancellationTokenSource(5000); // cancel after 5s
var worker = new Worker(cts.Token);
Task receiver = Task.Run(() => worker.ReceiverRun());
Task main = worker.ProcessAsync();
try
{
Task.WaitAll(main, receiver);
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message);
}
Worker.LogThread("Leave Main");
Console.ReadLine();
}
}
}
This is not much different from doing Task.Run(() => task.SetResult(msg)) inside ReceiverRun. The only advantage I can think of is that you have an explicit control over when to switch threads. This way, you can stay on the same thread for as long as possible (e.g., for task2, task3, task4, but you still need another thread switch after task4 to avoid a deadlock on task5.Wait()).
Both solutions would eventually make the thread pool grow, which is bad in terms of performance and scalability.
Now, if we replace task.Wait() with await task everywhere inside ProcessAsync in the above code, we will not have to use await Task.Yield and there still will be no deadlocks. However, the whole chain of await calls after the 1st await task1 inside ProcessAsync will actually be executed on the ReceiverRun thread. As long as we don't block this thread with other Wait()-style calls and don't do a lot of CPU-bound work as we're processing messages, this approach might work OK (asynchronous IO-bound await-style calls still should be OK, and they may actually trigger an implicit thread switch).
That said, I think you'd need a separate thread with a serializing synchronization context installed on it for processing messages (similar to WindowsFormsSynchronizationContext). That's where your asynchronous code containing awaits should run. You'd still need to avoid using Task.Wait on that thread. And if an individual message processing takes a lot of CPU-bound work, you should use Task.Run for such work. For async IO-bound calls, you could stay on the same thread.
You may want to look at ActionDispatcher/ActionDispatcherSynchronizationContext from #StephenCleary's
Nito Asynchronous Library for your asynchronous message processing logic. Hopefully, Stephen jumps in and provides a better answer.
"My assumption was that the second SendAwaitResponse would execute in a ThreadPool thread but it continues in the thread created for ReceiverRun."
It depends entirely on what you do within SendAwaitResponse. Asynchrony and concurrency are not the same thing.
Check out: C# 5 Async/Await - is it *concurrent*?
A little late to the party, but here's my solution which i think is added value.
I've been struggling with this also, i've solved it by capturing the SynchronizationContext on the method that is awaited.
It would look something like:
// just a default sync context
private readonly SynchronizationContext _defaultContext = new SynchronizationContext();
void ReceiverRun()
{
while (true) // <-- i would replace this with a cancellation token
{
var msg = ReadNextMessage();
TaskWithContext<TResult> task = requests[msg.RequestID];
// if it wasn't a winforms/wpf thread, it would be null
// we choose our default context (threadpool)
var context = task.Context ?? _defaultContext;
// execute it on the context which was captured where it was added. So it won't get completed on this thread.
context.Post(state =>
{
if (msg.Error == null)
task.TaskCompletionSource.SetResult(msg);
else
task.TaskCompletionSource.SetException(new Exception(msg.Error));
});
}
}
public static Task<Response> SendAwaitResponse(string msg)
{
// The key is here! Save the current synchronization context.
var t = new TaskWithContext<Response>(SynchronizationContext.Current);
requests.Add(GetID(msg), t);
stream.Write(msg);
return t.TaskCompletionSource.Task;
}
// class to hold a task and context
public class TaskWithContext<TResult>
{
public SynchronizationContext Context { get; }
public TaskCompletionSource<TResult> TaskCompletionSource { get; } = new TaskCompletionSource<Response>();
public TaskWithContext(SynchronizationContext context)
{
Context = context;
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Can anyone explain what the await function does?
They just talked about this at PDC yesterday!
Await is used in conjunction with Tasks (parallel programming) in .NET. It's a keyword being introduced in the next version of .NET. It more or less lets you "pause" the execution of a method to wait for the Task to complete execution. Here's a brief example:
//create and run a new task
Task<DataTable> dataTask = new Task<DataTable>(SomeCrazyDatabaseOperation);
//run some other code immediately after this task is started and running
ShowLoaderControl();
StartStoryboard();
//this will actually "pause" the code execution until the task completes. It doesn't lock the thread, but rather waits for the result, similar to an async callback
// please so also note, that the task needs to be started before it can be awaited. Otherwise it will never return
dataTask.Start();
DataTable table = await dataTask;
//Now we can perform operations on the Task result, as if we're executing code after the async operation completed
listBoxControl.DataContext = table;
StopStoryboard();
HideLoaderControl();
Basically, the async and await keywords allow you to specify that execution of a method should stop at all usages of await, which mark asynchronous method calls, and then resume once the asynchronous operation is complete. This allows you to call a method in an app's main thread and handle complex work asynchronously, without the need to explicitly define threads and joins or blocking the app's main thread.
Think of it as being somewhat similar to a yield return statement in a method producing an IEnumerable. When the runtime hits the yield, it will basically save the method's current state, and return the value or reference being yielded. The next time IEnumerator.MoveNext() is called on the return object (which is generated internally by the runtime), the method's old state is restored to the stack and execution continues with the next line after the yield return as if we'd never left the method. Without this keyword, an IEnumerator type must be custom-defined to store state and handle the iteration requests, with methods that can become VERY complex indeed.
Similarly, a method marked as async must have at least one await. On an await, the runtime will save the current thread's state and call stack, make the asynchronous call, and unwind back to the runtime's message loop to handle the next message and keep the app responsive. When the asynchronous operation is complete, at the next scheduling opportunity, the call stack to up the async operation is pushed back in and continued as if the call was synchronous.
So, these two new keywords basically simplify the coding of asynchronous processes, much like yield return simplified the generation of custom enumerables. With a couple keywords and a little background knowledge, you can skip all the confusing and often error-prone details of a traditional asynchronous pattern. This will be INVALUABLE in pretty much any event-driven GUI app like Winforms, WPF of Silverlight.
The currently accepted answer is misleading.
await is not pausing anything.
First of all it can be used only in methods or lambdas marked as async and returning Task or void if you don't care having Task instance running in this method.
Here is an illustration:
internal class Program
{
private static void Main(string[] args)
{
var task = DoWork();
Console.WriteLine("Task status: " + task.Status);
Console.WriteLine("Waiting for ENTER");
Console.ReadLine();
}
private static async Task DoWork()
{
Console.WriteLine("Entered DoWork(). Sleeping 3");
// imitating time consuming code
// in a real-world app this should be inside task,
// so method returns fast
Thread.Sleep(3000);
await Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("async task iteration " + i);
// imitating time consuming code
Thread.Sleep(1000);
}
});
Console.WriteLine("Exiting DoWork()");
}
}
Output:
Entered DoWork(). Sleeping 3
async task iteration 0
Task status: WaitingForActivation
Waiting for ENTER
async task iteration 1
async task iteration 2
async task iteration 3
async task iteration 4
async task iteration 5
async task iteration 6
async task iteration 7
async task iteration 8
async task iteration 9
Exiting DoWork()
For anyone new to asynchronous programming in .NET, here's a (totally fake) analogy in a scenario you may be more familiar with - AJAX calls using JavaScript/jQuery. A simple jQuery AJAX post looks like this:
$.post(url, values, function(data) {
// AJAX call completed, do something with returned data here
});
The reason we process the results in a callback function is so we don't block the current thread while waiting for the AJAX call to return. Only when the response is ready will the callback get fired, freeing the current thread to do other things in the mean time.
Now, if JavaScript supported the await keyword (which of course it doesn't (yet!)), you could achieve the same with this:
var data = await $.post(url, values);
// AJAX call completed, do something with returned data here
That's a lot cleaner, but it sure looks like we introduced synchronous, blocking code. But the (fake) JavaScript compiler would have taken everything after await and wired it into a callback, so at runtime the second example would behave just like the first.
It may not seem like it's saving you much work, but when it comes to things like exception handling and synchronization contexts, the compiler is actually doing a lot of heavy lifting for you. For more, I'd recommend the FAQs followed by Stephen Cleary's blog series.
If I had to implement it in Java it would look some thing like this:
/**
* #author Ilya Gazman
*/
public abstract class SynchronizedTask{
private ArrayList<Runnable> listeners = new ArrayList<Runnable>();
private static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(6, 6, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1000));
public final void await(Runnable listener){
synchronized (this) {
listeners.add(listener);
}
}
public void excecute(){
onExcecute();
for (int i = listeners.size() - 1; i >= 0; i--) {
Runnable runnable;
synchronized (this) {
runnable = listeners.remove(i);
}
threadPoolExecutor.execute(runnable);
}
}
protected abstract void onExcecute();
}
Your application would use it like this:
public class Test{
private Job job = new Job();
public Test() {
craeteSomeJobToRunInBackground();
methode1();
methode2();
}
private void methode1(){
System.out.println("Running methode 1");
job.await(new Runnable() {
#Override
public void run() {
System.out.println("Continue to running methode 1");
}
});
}
private void methode2(){
System.out.println("Running methode 2");
}
private void craeteSomeJobToRunInBackground() {
new Thread(new Runnable() {
#Override
public void run() {
job.excecute();
}
}).start();
}
private class Job extends SynchronizedTask{
#Override
protected void onExcecute() {
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Job is done");
}
}
}