c# async methods in asp.net mvc actions - c#

Let's have the following situation
// method from class A
public async Task FooAsync()
{
return Task.Factory.StartNew(() => { //code_block_1 });
}
// method from class B
public async Task BarAsync()
{
return Task.Factory.StartNew(() => { //code_block_2 });
}
and an action method in a MVC controller
public async void SomeAction()
{
A a = new A();
B b = new B();
Task t1 = a.FooAsync();
Task t2 = b.BarAsync();
// Some other code 1
await Task.WhenAll(t1, t2);
// Some other code 2
}
And a request to that action is sent. How I think everything should work:
A thread from the thread pool will be assigned to process the request
The execution of SomeAction() starts in that thread. "a" and "b" are created.
FooAsync() is called. Task.Factory.StartNew() is executed which creates new task for "//code_block_1". From that moment it's up to the TaskScheduler what thread from the thread pool will process the task. It could be the same thread executing "SomeAction" (in that case the execution of FooAsync would be synchronous) or another thread from the pool.
BarAsync() is called. [Same as above]
"// Some other code 1" is executed on the same thread on which SomeAction() started.
await Task.WhenAll(t1, t2); creates a task which waits until both t1 and t2 have completed. Everything after the "await" ("// Some other code 2") is marked as "continuation" and the current thread is release back to the pool. Once both t1 and t2 have completed, the rest of the code can be processed by a thread from the pool (not necessarily the same thread which started processing SomeAction()).
And finally my question... Am I right? Am I wrong about something and what is it? And am I missing something?

Yes, this is almost entirely accurate.
It could be the same thread executing "SomeAction"
If that was the case there would be no point in calling StartNew. This method is meant to create parallelism. It never inlines the task. You probably confused this with Wait inlining unstarted tasks.
Note, that because of the parallelism you initiated request processing will block 2 threads instead of one. Hadn't you used await it would have taken 3.

Related

Why will the synchronous continuations no longer be executed synchronously?

In the following article, Stephen Toub describes how to build a ManualResetEvent using the TPL. In particular, he states that in the following method:
public void Set()
{
var tcs = m_tcs;
Task.Factory.StartNew(
s => ((TaskCompletionSource<bool>)s).TrySetResult(true),
tcs,
CancellationToken.None,
TaskCreationOptions.PreferFairness,
TaskScheduler.Default);
tcs.Task.Wait();
}
the tcs.Task.Wait() will "block until the task being completed is actually finished (not including the task’s synchronous continuations, just the task itself)". Why won't we block on any synchronous continuations? That is, what will prevent any synchronous continuations on any Tasks awaiting tcs.Task's completion from executing synchronously?
He means that if you do is this way:
public void Set()
{
m_tsc.TrySetResult(true);
}
Then all synchronous continuations of TaskCompletionSource Task will run synchronously on this same thread, blocking Set method for the duration.
However if you do it the way described in your question, then all those continuations will still run, but on thread pool thread, because that's where you execute TrySetResult. As soon as TaskCompletionSource task completes - your tcs.Task.Wait() will return, before synchronous continuations will run. So in effect, Set method will not block waiting for them to complete.
This is because the work in ContinueWith is a different task. All ContinueWith variants say:
Returns
A new continuation Task.
and in the Remarks we can read:
Remarks
The returned Task will not be scheduled for execution until the current task has completed.
BTW. These days ContinueWith is discouraged and await is preferred in almost all cases.
the tcs.Task.Wait() will "block until the task being completed is actually finished (not including the task’s synchronous continuations, just the task itself)". Why won't we block on any synchronous continuations? That is, what will prevent any synchronous continuations on any Tasks awaiting tcs.Task's completion from executing synchronously?
Your question is about Tasks in general, not about the TaskCompletionSource.Task in particular. The answer is that when an incomplete Task is waited, the Wait is performed by a ManualResetEventSlim, which is Set by a task continuation, which is prioritized in front of all other continuations that might be attached previously. Here is a part of the private SpinThenBlockingWait method, from the Task.cs source code:
private bool SpinThenBlockingWait(int millisecondsTimeout,
CancellationToken cancellationToken)
{
bool infiniteWait = millisecondsTimeout == Timeout.Infinite;
uint startTimeTicks = infiniteWait ? 0 : (uint)Environment.TickCount;
bool returnValue = SpinWait(millisecondsTimeout);
if (!returnValue)
{
var mres = new SetOnInvokeMres();
try
{
AddCompletionAction(mres, addBeforeOthers: true);
if (infiniteWait)
{
bool notifyWhenUnblocked = ThreadPool.NotifyThreadBlocked();
try
{
returnValue = mres.Wait(Timeout.Infinite, cancellationToken);
//...
This method is invoked internally by the Wait, when the task is not complete at the moment, and the current thread must be blocked. The SetOnInvokeMres is a small class that inherits from the ManualResetEventSlim:
private sealed class SetOnInvokeMres : ManualResetEventSlim, ITaskCompletionAction
{
internal SetOnInvokeMres() : base(false, 0) { }
public void Invoke(Task completingTask) { Set(); }
public bool InvokeMayRunArbitraryCode => false;
}
The interesting point is the addBeforeOthers: true argument. This ensures that the ManualResetEventSlim will be signaled before invoking any continuation that is associated with user-supplied code. The Task Parallel Library exposes no public API that allows to attach a continuation with addBeforeOthers: true. Actually this parameter seems to exist exclusively for supporting the signaling of ManualResetEventSlims with priority.

AppDomain.Unload throws ThreadAbortException exception

Having
public class ObjFromOtherAppDomain : MarshalByRefObject
{
public async void Do(MarshalableCompletionSource<bool> source)
{
await Task.Delay(1000);
source.SetResult(true);
}
}
public class MarshalableCompletionSource<T> : MarshalByRefObject
{
private readonly TaskCompletionSource<T> tsc = new TaskCompletionSource<T>();
public void SetResult(T result) => tsc.SetResult(result);
public void SetException(Exception[] exception) => tsc.SetException(exception);
public void SetCanceled() => tsc.SetCanceled();
public Task<T> Task => tsc.Task;
}
Doing
Create new AppDomain
Create an instance of ObjFromOtherAppDomain within the new AppDomain
invoke Do method passing MarshalableCompletionSource in order later to know when async Do method is completed.
Once Do method is completed, trying to Unload the AppDomain
public static async Task Main()
{
var otherDomain = AppDomain.CreateDomain("other domain");
var objFromOtherAppDomain = (ObjFromOtherAppDomain)otherDomain
.CreateInstanceAndUnwrap(
typeof(ObjFromOtherAppDomain).Assembly.FullName,
typeof(ObjFromOtherAppDomain).FullName);
var source = new MarshalableCompletionSource<bool>();
objFromOtherAppDomain.Do(source);
await source.Task;
//await Task.Yield();
AppDomain.Unload(otherDomain);
}
Getting
System.Threading.ThreadAbortException: 'Thread has aborted. (Exception
from HRESULT: 0x80131530) exception
Fix
Uncomment await Task.Yield(); line and Unload works well.
Short analysis
Main thread enters Do method and on the line await Task.Delay(1000), Main thread returns back to Main method, while new background thread gets pulled from ThreadPool (it's happening in otherDomain) and continues execution of continuation, in this case, rest of the Do method.
After that, the same (background) thread starts executing rest of the Main method (the part after await source.Task)
At that moment background thread hits AppDomain.Unload(otherDomain), it should be done in otherDomain and happily unload it, but, apparently, it's not.
If i'll yield (release, set free) that background thread by await Task.Yield(), new Background thread comes into play and does AppDomain.Unload happily.
Why is that?
With the help of my colleague, I found out the issue.
Short
When the result is set to TaskCompletionSource, continuation attached to TaskCompletionSource.Task runs on the same thread that called TaskCompletionSource.SetResult, causing Do method not to be completed at the time AppDomain.Unload is called.
Detailed
Main -> objFromOtherAppDomain.Do(source); - Thread1 starts execution of Do method
Do -> await Task.Delay(1000); - Thread1 returns back to Main method and awaits source.Task, Thread2 continues execution of Do method.
Do -> source.SetResult(true); - Thread2 sets the result to MarshalableCompletionSource.Task and continues execution of Main method (Without finishing up the Do method)
Main -> AppDomain.Unload(otherDomain); - Thread2 tries to unload the AppDomain, but since Do method isn't yet finished, unload fails.
On the other hand, if we do await Task.Yield(), it will cause Thread2 to return from Main method to Do method and finish it up, after that AppDomain can be unloaded.
Related
Calling TaskCompletionSource.SetResult in a non blocking manner

Why is the initial thread not used on the code after the awaited method?

I do not understand how is the control returned to the caller when using async- await, since when i execute this code, the first thread gets practically destroyed when calling task inside the awaited method, and the thread that gives the result executes all remaining code.Below i have also drawn a diagram of how i thought the execution is, but it seems it is wrong.
Assumed workflow according to "returning control to the caller":
Results
Main
public static string GetThreadId => Thread.CurrentThread.ManagedThreadId.ToString();
static async Task Main(string[] args) {
Console.WriteLine("From main before async call , Thread:" + GetThreadId);
string myresult = await TestAsyncSimple();
Console.WriteLine("From main after async call ,Thread:" + GetThreadId);
Console.WriteLine("ResultComputed:" + myresult+",Thread:"+GetThreadId);
Console.ReadKey();
}
Async Task
public static async Task<string> TestAsyncSimple() {
Console.WriteLine("From TestAsyncSimple before delay,Thread:" + GetThreadId);
string result=await Task.Factory.StartNew(() => {
Task.Delay(5000);
Console.WriteLine("From TestAsyncSimple inside Task,Thread:" + GetThreadId);
return "tadaa";
});
Console.WriteLine("From TestAsyncSimple after delay,Thread:" + GetThreadId);
return result;
}
Can anyone point me to the right direction?Also what causes the new thread to get spawned?Always when starting a Task ?Are there other "triggers" besides tasks that create new threads which will execute the remaining code?
async Main method is converted to something like this:
static void Main() {
RealMain().GetAwaiter().GetResult();
}
static async Task RealMain() {
// code from async Main
}
With that in mind, at "From main before async call" point you are on main application thread (id 1). This is regular (non thread pool) thread. You will be on this thread until
await Task.Factory.StartNew(...)
At this point, StartNew starts a new task which will run on a thread pool thread, which is created or grabbed from pool if already available. This is thread 3 in your example.
When you reach await - control is returned back to the caller, where caller in this case is thread 1. What this thread does after await is reched? It's blocked here:
RealMain().GetAwaiter().GetResult();
waiting for result of RealMain.
Now thread 3 has finished execution but TestAsyncSimple() has more code to run. If there were no synchronization context before await (the case here - in console application) - the part after await will be executed on available thread pool thread. Since thread 3 has finished execution of its task - it is available and is capable to continue execution of the rest of TestAsyncSimple() and Main() functions, which it does. Thread 1 all this time is blocked as said above - so it cannot process any continuations (it's busy). In addition it's also not a thread pool thread (but that is not relevent here).
After you reached Console.ReadKey and pressed a key - Main task finally completes, thread 1 (waiting for this task to complete) is unblocked, then it returns from real Main function and process is terminated (only at this point thread 1 is "destroyed").

Does a method has to be async when invoked inside an async method?

Lets say I have a method defined as follows:
public async Task CreateUser()
{
await GetUserDetails();
GetUserOrder();
}
private void GetUserDetails() {
private void GetUserOrder() {
Does the method GetUserDetails(); and GetUserOrder() have to be async as well to avoid UI blocking ?
I cannot await the GetUserDetails() method since it is not async. How can I achieve this in c# ? I want to ensure all these methods are invoked step by step.
The relevant question is in a comment:
How can I ensure all my methods are invoked completely sequentially?
The fact that you're asking the question indicates that you don't understand what "await" is. Await is the sequencing operation on a asynchronous workflows. An await means this workflow will not proceed until the awaited task is complete. It's an asynchronous wait, hence the name await.
Consider this question: in a synchronous workflow, what is the sequencing operation?
No, really, give it some thought.
.
.
.
It is ;. When you say
fResult = foo();
bResult = bar();
qResult = qux();
that means that foo has to finish completely before bar can begin. That is not true for asynchronous workflows. If we have
fTask = fooAsync();
bTask = barAsync();
qTask = quxAsync();
Then the asynchronous operations can complete in any order. If we say
await fooAsync();
await barAsync();
await quxAsync();
Then barAsync will not start until fooAsync's task completes. await sequences the asynchronous workflow. The difference is that the thread can continue to do other unrelated work while asynchronously waiting for foo to complete, which is not true in a synchronous workflow; in a synchronous workflow the thread is already busy computing the foo result, so it can't do other work.
yes if you want to wait than you have to write await for that methods also. because after first await your code agian will be synchronous ..and if UI thread than it will run on it.
1.you code will be , so by this code you code become asynchronous for GetUserORder also. you just have to wrap method in Task construct and return
public async Task CreateUser()
{
await GetUserDetails();
await Task.Factory.SartNew(()=> GetUserOrder());
}
2.or you can do this also
public async Task CreateUser()
{
await Task.Factory.SartNew(()=>{
GetUserDetails();
GetUserOrder(); });
}
3.or you can do like this also, in below code will not wait for getuserorder method and excute await one method
public async Task CreateUser()
{
Task.Factory.SartNew(()=> GetUserOrder()).ContinueWith((t)=> Console.WriteLine("Completed");
await GetUserDetails();
}
4.or last one variation, here you start GetUserOrder first and dont wait for it than you call GetUserDetails in async fashion , and if you want to work on GetUserOrder method want to wait just use Wait method.
public async Task CreateUser()
{
var task = Task.Factory.SartNew(()=> GetUserOrder());
await GetUserDetails();
if(!task.IsCompleted)
task.Wait();
}
in your case you can go for 3 and if you want to wait go for 4th one.
As you asked me in comment what is difference between Task.Run and statnew method -: for that you can check this SO question : Regarding usage of Task.Start() , Task.Run() and Task.Factory.StartNew()
You should put await only in front of async methods. To run a synchronous one that you don't want to wait, you can use a new thread from the tread pool:
new Thread(() => DoSomething()).Start();
or
Task.Factory.SartNew(()=> DoSomething());
Here is the help page: https://msdn.microsoft.com/en-us/library/dd321439(v=vs.110).aspx
Otherwise, your call to GetUserDetails will have to finish before you execute the next line.

Asyc method using await Task.Run() never "completes"

I have a method that is defined as
public async Task SomeAsyncMethod()
{
DoSomeStuff();
await Task.Run(() => {
DoSomeSyncStuff();
DoSomeOtherSyncStuff();
});
var someDebugVariable = "someDebugValue";
}
The method itself does exactly what it is supposed to do and everything runs fine. Yet ... it looks like the "outer" async Task never completes.
Example: When I call it like this
public void CallerMethod()
{
Task t = SomeAsyncMethod();
t.Wait();
}
the t.Wait() never completes. Furthermore: if I place a breakpoint at the assignment of someDebugVariable it never gets hit.
I might add that DoSomeSyncStuff and DoSomeOtherSyncStuff really do what they are supposed to and debugging through them tells me that they both complete.
To prove my point I modified my method like this, and the results are still the same.
public async Task SomeAsyncMethod()
{
DoSomeStuff();
await Task.Run(() => {
/*
DoSomeSyncStuff();
DoSomeOtherSyncStuff();
*/
var a = 2; var b = 3; var c = a + b;
});
var someDebugVariable = "someDebugValue";
}
EDIT
I have tried removing everything but the await Task.Run and it does not change anything. It still does not complete.
The application is a WPF application. The caller thread is the UI thread.
What am I missing here?
The t.Wait() call is causing a deadlock, and also makes the async call entirely pointless. I believe if you change the code to
await Task.Run(() => {
// ...
}).ConfigureAwait(false);
You can fix the deadlock and let the code proceed, but you should really get rid of the t.Wait() call. Anything that needs to be done with the results of the sync function calls should be done after the awaited task, not after the call of the async function.
More in depth:
task.Wait() will block all execution on the main thread while the task is running. When the await task completes, it tries to marshall back to the main thread, but the main thread is blocked! Since A is waiting for B, and B is waiting for A, you get a deadlock.
See: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Categories

Resources