Async method not running in parallel - c#

In the following code, in the B method, the code Trace.TraceInformation("B - Started"); never gets called.
Should the method be running in parallel?
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
private static async Task A()
{
for (;;)
{
}
}
private static async Task B()
{
Trace.TraceInformation("B - Started");
}
static void Main(string[] args)
{
var tasks = new List<Task> { A(), B() };
Task.WaitAll(tasks.ToArray());
}
}
}

Short answer
No, as you wrote your two async methods, they are indeed not running in parallel. Adding await Task.Yield(); to your first method (e.g. inside the loop) would allow them to do so, but there are more reasonable and straightforward methods, highly depending on what you actually need (interleaved execution on a single thread? Actual parallel execution on multiple threads?).
Long answer
First of all, declaring functions as async does not inherently make them run asynchronously or something. It rather simplifies the syntax to do so - read more about the concepts here: Asynchronous Programming with Async and Await
Effectively A is not asynchronous at all, as there is not a single await inside its method body. Instructions up to the first use of await run synchronously like a regular method would.
From then on, the object that you await determines what happens next, i.e. the context that the remaining method runs in.
To force execution of a task to happen on another thread, use Task.Run or similar.
In this scenario, adding await Task.Yield() does the trick since the current synchronization context is null and this happens to indeed cause the task scheduler (should be ThreadPoolTaskScheduler) to execute the remaining instuctions on a thread-pool thread - some environment or configuration might cause you to only have one of them, so things would still not run in parallel.
Summary
The moral of the story is: Be aware of the differences between two concepts:
concurrency (which is enabled by using async/await reasonably) and
parallelism (which only happens when concurrent tasks get scheduled the right way or if you enforce it using Task.Run, Thread, etc. in which case the use of async is completely irrelevant anyway)

The async modifier is not a magic spawn-a-thread-here marker. It's sole purpose is to let the compiler know a method might depend on some asynchronous operation (A complex data-processing thread, I/O...) so it has to setup a state machine to coordinate the callbacks resulting from those asynchronous operations.
To make A run on another thread you would invoke it using Task.Run which wraps the invocation on a new thread with a Task object, which you can await. Be aware that await-ing a method does not mean your code runs in parallel to A's execution all by itself: It will until the very line you await the Task object, telling the compiler you need the value that the Task object returns. In this case await-ing Task.Run(A) will effectively make your program run forever, waiting for A to return, something that will never happen (barring computer malfunction).
Do have in mind that marking a method as async but not actually awaiting anything will only have the effect of a compiler warning. If you await something that is not truly async (It returns immediately on the calling thread with something like Task.FromResult) it will mean your program takes a runtime speed penalty. It is very slight, however.

No, the methods shown are not expected to "run in parallel".
Why B is never called - you have list of tasks tasks constructed via essentially series of .Add calls - and first is result of A() is added. Since the A method does not have any await it will run to the completion synchronously on the same thread. And after that B() would be called.
Now A will never complete (it is sitting in infinite loop) so really code will not even reach call to B.
Note that even if creation would succeed code never finish WaitAll as A still sits in infinite loop.
If you want methods to "run in parallel" you need to either run them implicitly/explicitly on new threads (i.e. with Task.Run or Thread.Start) or for I/O bound calls let method to release thread with await.

Related

Effects of async within a parallel for loop

I am going to start by saying that I am learning about mulithreading at the moment so it may be the case that not all I say is correct - please feel free to correct me as required. I do have a reasonable understanding of async and await.
My basic aim is as follows:
I have a body of code that currently takes about 3 seconds. I am trying to load some data at the start of the method that will be used right at the end. My plan is to load the data on a different thread right at the start - allowing the rest of the code to execute independently. Then, at the point that I need the data, the code will wait if the data is not loaded. So far this is all seems to be working fine and as I describe.
My question relates to what happens when I call a method that is async, within a parallel for loop, without awaiting it.
My code follows this structure:
public void MainCaller()
{
List<int> listFromThread = null;
var secondThread = Task.Factory.StartNew(() =>
{
listFromThread = GetAllLists().Result;
});
//Do some other stuff
secondThread.Wait();
//Do not pass this point until this thread has completed
}
public Task<List<int>> GetAllLists()
{
var intList = new List<int>(){ /*Whatever... */};
var returnList = new List<int>();
Parallel.ForEach(intList, intEntry =>
{
var res = MyMethod().Result;
returnList.AddRange(res);
});
return Task.FromResult(returnList);
}
private async Task<List<int>> MyMethod()
{
var myList = await obtainList.ToListAsync();
}
Note the Parallel for Loop calls the async method, but does not await it as it is not async itself.
This is a method that is used elsewhere, so it is valid that it is async. I know one option is to make a copy of this method that is not async, but I am trying to understand what will happen here.
My question is, can I be sure that when I reach secondThread.Wait(); the async part of the execution will be complete. Eg will wait to know wait for the async part to complete, or will async mess up the wait, or will it work seamlessly together?
It seems to me it could be possible that as the call to MyMethod is not awaited, but there is an await within MyMethod, the parallel for loop could continue execution before the awaited call has completed?
Then I think, as it is assigning it by reference, then once the assigning takes place, the value will be the correct result.
This leads me to think that as long as the wait will know to wait for the async to complete, then there is no problem - hence my question.
I guess this relates to my lack of understanding of Tasks?
I hope this is clear?
In your code there is no part that is executed asynchrounously.
In MainCaller, you start a Task and immediately Wait for it to finished.
This is a blocking operation which only introduces the extra overhead of calling
GetAllLists in another Task.
In this Task you call You start a new Task (by calling GettAllLists) but immediately
wait for this Task to finish by waiting for its Result (which is also blocking).
In the Task started by GetAllLists you have the Parallel.Foreach loop which starts
several new Tasks. Each of these 'for' Tasks will start another Task by calling
MyMethod and immediately waiting for its result.
The net result is that your code completely executes synchronously. The only parallelism is introduced in the Parallel.For loop.
Hint: a usefull thread concerning this topic: Using async/await for multiple tasks
Additionally your code contains a serious bug:
Each Task created by the Parallel.For loop will eventually add its partial List to the ReturnList by calling AddRange. 'AddRange' is not thread safe, so you need to have some synchronisation mechanism (e.g. 'Lock') or there is the possibility that your ReturnList gets corrupted or does not contain all the results. See also: Is the List<T>.AddRange() thread safe?

which is the difference between task.whenAll and configurewait?

I have an async method that get data from a database:
private async Task getDataAsync()
{
await getDataFromDatabaseAsync();
}
I have a contructor that uses this method, in this way:
public MyViewModel()
{
Task.WhenAll(getDataAsync());
//getDataAsync().ConfigureAwait(false);
//next line of code
}
The only way that I get to avoid the applications isn't blocked is using one the two options, both seems to work fine. I can use WhenAll or I can use ConfigureAwait(false).
Another options it is calling the method getDataASync() inside a task, but I guess it is a worse option becase it takes more resources.
So I would like to know which is the differences between WhenAll and ConfigureAwait.
When I use WhenAll in this way, the line of code "next line of code" is run after the async method is finisihed or it will run before finish?
Thanks.
There is a common misconception that when you make a method async, it will be actually executed asynchronously (i.e. on a separate thread). That is not the case: async and await are a means to synchronize already asnychronous code. If you have nothing that is executed on a separate thread, your async code will run fully synchronously to the end.
Since getDataAsync is executed on the same thread as the MyViewModel constructor, you can run into a deadlock, since the thread waits for itself. When you use ConfigureAwait, you can avoid this situation.
Whether you actually should do that is a different question. What you are actually doing with ConfigureAwait is to start the task and to allow the await to continue on a separate context (which can be on a separate thread). Apart from the fact that you are not even using await here, continuation in a different context can become a problem when you want to execute UI operations after the await.
If you want to be sure that you can wait for getDataAsync in your constructor, you can use Task.Run to force execution in the thread pool:
var getDataTask = Task.Run((Func<Task>)getDataAsync);
//Do something else
getDataTask.Wait();
Everything you execute between Task.Run and the Wait() can run during the execution of getDataAsync. Whether parallelism is actually worth it here depends on what else you do until the Wait().
What you are doing in the MyViewModel constructor is to finally synchronize all asynchronous operations and make the execution of the constructor synchronous. If you want to run that operation asynchronously, you would need to start another task to do it. So you should be really sure that beyond that point async is not required anymore. If it is, run the initialization on another async method, await getDataAsync() there and synchronize somewhere up the call chain.

Are non-thread-safe functions async safe?

Consider the following async function that modifies a non-thread-safe list:
async Task AddNewToList(List<Item> list)
{
// Suppose load takes a few seconds
Item item = await LoadNextItem();
list.Add(item);
}
Simply put: Is this safe?
My concern is that one may invoke the async method, and then while it's loading (either on another thread, or as an I/O operation), the caller may modify the list.
Suppose that the caller is partway through the execution of list.Clear(), for example, and suddenly the Load method finishes! What will happen?
Will the task immediately interrupt and run the list.Add(item); code? Or will it wait until the main thread is done with all scheduled CPU tasks (ie: wait for Clear() to finish), before running the code?
Edit: Since I've basically answered this for myself below, here's a bonus question: Why? Why does it immediately interrupt instead of waiting for CPU bound operations to complete? It seems counter-intuitive to not queue itself up, which would be completely safe.
Edit: Here's a different example I tested myself. The comments indicate the order of execution. I am disappointed!
TaskCompletionSource<bool> source;
private async void buttonPrime_click(object sender, EventArgs e)
{
source = new TaskCompletionSource<bool>(); // 1
await source.Task; // 2
source = null; // 4
}
private void buttonEnd_click(object sender, EventArgs e)
{
source.SetResult(true); // 3
MessageBox.Show(source.ToString()); // 5 and exception is thrown
}
No, its not safe. However also consider that the caller might also have spawned a thread and passed the List to its child thread before calling your code, even in a non async environment, which will have the same detrimental effect.
So; although not safe, there is nothing inherently thread-safe about receiving a List from a caller anyway - there is no way of knowing whether the list is actually being processed from other threads that your own.
Short answer
You always need to be careful using async.
Longer answer
It depends on your SynchronizationContext and TaskScheduler, and what you mean by "safe."
When your code awaits something, it creates a continuation and wraps it in a task, which is then posted to the current SynchronizationContext's TaskScheduler. The context will then determine when and where the continuation will run. The default scheduler simply uses the thread pool, but different types of applications can extend the scheduler and provide more sophisticated synchronization logic.
If you are writing an application that has no SynchronizationContext (for example, a console application, or anything in .NET core), the continuation is simply put on the thread pool, and could execute in parallel with your main thread. In this case you must use lock or synchronized objects such as ConcurrentDictionary<> instead of Dictionary<>, for anything other than local references or references that are closed with the task.
If you are writing a WinForms application, the continuations are put in the message queue, and will all execute on the main thread. This makes it safe to use non-synchronized objects. However, there are other worries, such as deadlocks. And of course if you spawn any threads, you must make sure they use lock or Concurrent objects, and any UI invocations must be marshaled back to the UI thread. Also, if you are nutty enough to write a WinForms application with more than one message pump (this is highly unusual) you'd need to worry about synchronizing any common variables.
If you are writing an ASP.NET application, the SynchronizationContext will ensure that, for a given request, no two threads are executing at the same time. Your continuation might run on a different thread (due to a performance feature known as thread agility), but they will always have the same SynchronizationContext and you are guaranteed that no two threads will access your variables at the same time (assuming, of course, they are not static, in which case they span across HTTP requests and must be synchronized). In addition, the pipeline will block parallel requests for the same session so that they execute in series, so your session state is also protected from threading concerns. However you still need to worry about deadlocks.
And of course you can write your own SynchronizationContext and assign it to your threads, meaning that you specify your own synchronization rules that will be used with async.
See also How do yield and await implement flow of control in .NET?
Assuming the "invalid acces" occures in LoadNextItem(): The Task will throw an exception. Since the context is captured it will pass on to the callers thread so list.Add will not be reached.
So, no it's not thread-safe.
Yes I think that could be a problem.
I would return item and add to the list on the main tread.
private async void GetIntButton(object sender, RoutedEventArgs e)
{
List<int> Ints = new List<int>();
Ints.Add(await GetInt());
}
private async Task<int> GetInt()
{
await Task.Delay(100);
return 1;
}
But you have to call from and async so I do not this this would work either.

what is the purpose of running task synchronously and when to do it?

what is the purpose of running task synchronously
public static void RunMeSync()
{
for(int i = 0; i < 9999; i++)
{
ListBox1.Items.Add(i.ToString());
}
}
public static void Main()
{
Task T1 = new Task(()=>RunMeSync);
T1.RunSynchronously();
Task T2 = Task.Run(()=>RunMeSync);
}
is it pointless to do so ? what is the need to run task synchronously ?
Consider the following code snippet
public static void Main()
{
Task T1 = new Task(()=>RunMeSync);
T1.RunSynchronously();
RunMeSync();
}
is it the same thing running T1 Synchronously, invoking RunMeSync directly?
Is it the same thing running T1 Synchronously, invoking RunMeSync directly?
Yes, the effect is going to be the same. You would not gain anything by running synchronously a task constructed from a method that you could call directly.
However, not all tasks are like that: some are constructed from methods to which you have no access - for example, tasks passed into your class as parameters. In other cases a task would have no named method associated with it, because it is constructed from a lambda or with an anonymous delegate. In all these cases, RunSynchronously() provides a way to calling the logic that implements the task, without knowing or worrying about the way in which that logic has been defined.
A Task itself is just a unit of work - and as-such, is agnostic to how it is run.
It's entirely up to you to determine how it is run, based upon the needs, constraints and context of your program (albeit defaulting to potentially running in parallel)
The name RunSynchronously is a quite a bit of misnomer, better name would be TryToRunSynchronously. Method will wait for the task to complete anyway irrespective of which thread it ran, maybe that's why they picked up this name.
Yes, as the name suggests Task will not be always run synchronously in current thread. If the underlying scheduler refuses to inline, Task will still be queued for execution and wait for it to complete. TaskScheduler.TryExecuteTaskInline decides whether the Task is a candidate for inlining or not, another one parameter deciding the task inlining is the amount of stack available. So it is not same as calling the method synchronously.
It might be helpful when you're dealing with some very deep recursive algorithms. Very deep recursion can cause StackOverflowException, you can check whether you have enough stack to proceed the recursion, if not just execute the Task in another thread (In fact that's how it is implemented).
Consider we are parallelizing some work. We split the work across threads and each of them does some deep recursion, If you're doing this with traditional recursive function, you'll end up with StackOverflowException. But if you wrap the recursive method logic inside Task.RunSynchronously then it will automatically stop recursing and queue the task to the underlying Scheduler and wait for it to complete if there is not enough stack available.

Async/Await - is it *concurrent*?

I've been considering the new async stuff in C# 5, and one particular question came up.
I understand that the await keyword is a neat compiler trick/syntactic sugar to implement continuation passing, where the remainder of the method is broken up into Task objects and queued-up to be run in order, but where control is returned to the calling method.
My problem is that I've heard that currently this is all on a single thread. Does this mean that this async stuff is really just a way of turning continuation code into Task objects and then calling Application.DoEvents() after each task completes before starting the next one?
Or am I missing something? (This part of the question is rhetorical - I'm fully aware I'm missing something :) )
It is concurrent, in the sense that many outstanding asychronous operations may be in progress at any time. It may or may not be multithreaded.
By default, await will schedule the continuation back to the "current execution context". The "current execution context" is defined as SynchronizationContext.Current if it is non-null, or TaskScheduler.Current if there's no SynchronizationContext.
You can override this default behavior by calling ConfigureAwait and passing false for the continueOnCapturedContext parameter. In that case, the continuation will not be scheduled back to that execution context. This usually means it will be run on a threadpool thread.
Unless you're writing library code, the default behavior is exactly what's desired. WinForms, WPF, and Silverlight (i.e., all the UI frameworks) supply a SynchronizationContext, so the continuation executes on the UI thread (and can safely access UI objects). ASP.NET also supplies a SynchronizationContext that ensures the continuation executes in the correct request context.
Other threads (including threadpool threads, Thread, and BackgroundWorker) do not supply a SynchronizationContext. So Console apps and Win32 services by default do not have a SynchronizationContext at all. In this situation, continuations execute on threadpool threads. This is why Console app demos using await/async include a call to Console.ReadLine/ReadKey or do a blocking Wait on a Task.
If you find yourself needing a SynchronizationContext, you can use AsyncContext from my Nito.AsyncEx library; it basically just provides an async-compatible "main loop" with a SynchronizationContext. I find it useful for Console apps and unit tests (VS2012 now has built-in support for async Task unit tests).
For more information about SynchronizationContext, see my Feb MSDN article.
At no time is DoEvents or an equivalent called; rather, control flow returns all the way out, and the continuation (the rest of the function) is scheduled to be run later. This is a much cleaner solution because it doesn't cause reentrancy issues like you would have if DoEvents was used.
The whole idea behind async/await is that it performs continuation passing nicely, and doesn't allocate a new thread for the operation. The continuation may occur on a new thread, it may continue on the same thread.
The real "meat" (the asynchronous) part of async/await is normally done separately and the communication to the caller is done through TaskCompletionSource. As written here http://blogs.msdn.com/b/pfxteam/archive/2009/06/02/9685804.aspx
The TaskCompletionSource type serves two related purposes, both alluded to by its name: it is a source for creating a task, and the source for that task’s completion. In essence, a TaskCompletionSource acts as the producer for a Task and its completion.
and the example is quite clear:
public static Task<T> RunAsync<T>(Func<T> function)
{
if (function == null) throw new ArgumentNullException(“function”);
var tcs = new TaskCompletionSource<T>();
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
T result = function();
tcs.SetResult(result);
}
catch(Exception exc) { tcs.SetException(exc); }
});
return tcs.Task;
}
Through the TaskCompletionSource you have access to a Task object that you can await, but it isn't through the async/await keywords that you created the multithreading.
Note that when many "slow" functions will be converted to the async/await syntax, you won't need to use TaskCompletionSource very much. They'll use it internally (but in the end somewhere there must be a TaskCompletionSource to have an asynchronous result)
The way I like to explain it is that the "await" keyword simply waits for a task to finish but yields execution to the calling thread while it waits. It then returns the result of the Task and continues from the statement after the "await" keyword once the Task is complete.
Some people I have noticed seem to think that the Task is run in the same thread as the calling thread, this is incorrect and can be proved by trying to alter a Windows.Forms GUI element within the method that await calls. However, the continuation is run in the calling thread where ever possible.
Its just a neat way of not having to have callback delegates or event handlers for when the Task completes.
I feel like this question needs a simpler answer for people. So I'm going to oversimplify.
The fact is, if you save the Tasks and don't await them, then async/await is "concurrent".
var a = await LongTask1(x);
var b = await LongTask2(y);
var c = ShortTask(a, b);
is not concurrent. LongTask1 will complete before LongTask2 starts.
var a = LongTask1(x);
var b = LongTask2(y);
var c = ShortTask(await a, await b);
is concurrent.
While I also urge people to get a deeper understanding and read up on this, you can use async/await for concurrency, and it's pretty simple.

Categories

Resources