In terms of parallelism are these equivalent?
async Task TestMethod1()
{
Task<int> t1 = GetInt1();
Task<int> t2 = GetInt2();
await Task.WhenAll(t1, t2);
}
async Task TestMethod2()
{
Task<int> t1 = GetInt1();
await GetInt2();
await t1;
}
In TestMethod2, I am mainly interested in understanding whether GetInt1() starts executing while awaiting GetInt2().
Yes, in terms of "parallelism" (actually concurrency), they are pretty much the same.
In particular, the TAP docs state that returned tasks are "hot", that is:
All tasks that are returned from TAP methods must be activated... Consumers of a TAP method may safely assume that the returned task is active
So, your code is starting the asynchronous operations by calling their methods. The tasks they return are already in progress. In both examples, both tasks are running concurrently.
It doesn't matter terribly much whether you use two awaits or a single await Task.WhenAll. I prefer the Task.WhenAll approach because IMO it more clearly communicates the intent of concurrency. Also, it only interrupts the source context (e.g., UI thread) once instead of twice, but that's just a minor concern.
Related
I have this piece of code in my .netcore application
[HttpPost]
[Route("doSomething")]
public async Task<IActionResult> DoSomethingAsync([FromBody] Input input)
{
// Do Something
var task1 = Task.Run(async () =>
{
await taskFactory.DoTask(input);
});
// Do Something Differently
var task2 = Task.Run(async () =>
{
await taskFactory.DoAnotherTask(input);
});
await Task.WhenAll(task1, task2);
return Accepted();
}
DoTask() and DoAnotherTask() are both independent of each other and can be executed in parallel but they have to be awaited until both of them are in completed status.
So, I created two tasks and awaited them using Task.WhenAll().
But I have got a review comment to not use Task.Run() in an async method as it can lead to thread pool starvation.
Question 1: How does my code leading to thread pool starvation?
Question 2: If it is leading to thread pool starvation, how can I run both tasks in parallel?
To answer your question with confidence we must know the implementation of the DoTask and DoAnotherTask methods. Without knowing it we could just assume that they are implemented properly and follow the etiquette for async methods, which is to return a Task immediately, without blocking the calling thread. Under this assumption, the answer is: No, your code doesn't lead to thread pool starvation. This is because the ThreadPool thread employed by Task.Run has a negligible amount of work to do, which is just to create a Task object, so it will be returned back to the ThreadPool almost immediately.
It should be pointed out that although wrapping well behaved async delegates with Task.Run has negligible impact to the health of the ThreadPool, it offers no benefit either. Take a look at this semi-related question: Is Task.Run considered bad practice in an ASP .NET MVC Web Application?
For your thread pool starvation question, if you run a task, which is already async, executes 2 new Tasks, with task.run and inside that you run 2 async methods you have per call 5 Tasks, then you await the completion of both and you are at 6 Tasks per Request.
I usually do smth like this, you still have 4 Tasks, but in the end the pool would last longer.
[HttpPost]
[Route("doSomething")]
public async Task<IActionResult> DoSomethingAsync([FromBody] Input input)
{
// Do Something
var t1 = taskFactory.DoTask(input);
// Do Something Differently
var t2 = taskFactory.DoAnotherTask(input);
await Task.WhenAll(t1, t2);
return Accepted();
}
I have a method that has the async keyword with a task. This method returns a string that comes from JwtSecurityTokenHandler().WriteToken(t); The thing is none of the assignments in the body of the method are awaitable.I get the warning CS-1998. That says you shouldnt use async for synchronous methods which makes complete sense. But then it adds that you can use await Task.Run(() => { . So is it good practice to do this?
public async Task<object> GenerateMyUserJwtToken(string email, IdentityUser user)
//code that isnt awaitable
{
var u = await Task.Run(() =>
{
return new JwtSecurityTokenHandler().WriteToken(token);
});
return u;
}
edit: I did not ask what the error was I asked if it was a good idea to Implement await Task.Run(() on an async method signature that has no await assignments. I also asked that another async method is awaiting this in the another method here is the code
//awaiting method:
public async Task<object> LoginAsync(LoginDto model)
{
return await GenerateMyUserJwtToken(model.Email, appUser);
}
//controller:
[HttpPost("login")]
public async Task<object> Login([FromBody] LoginDto model)
{
var logMeIn = await new AuthUserService().LoginAsync(model);
return logMeIn; //returns token
}
My Question is is this async all the way or does the task.Run stop that process?
Using Task.Run just to make something sync is generally a bad practice but it cannot be stated generally.
If the sync method to execute may take for a long time, then it can be a solution. Please note that Task.Run will assign the task to a pool thread and it is not always desirable. It is a common misunderstanding that async methods always use or should use threads somewhere at the end of the async-await chain. However, async-await has nothing to do with threads, it is about asynchronicity (chaining deferred tasks) and creating threads is just one option to create awaitable tasks.
So what are the options?
The method to call is fast and never blocks the caller for long time (>100ms or so): do not use async at all. In this case Task<T>.FromResult(result) is a tempting solution but is highly discouraged because it is misleading for the caller. Use it only in unit tests or if you are forced to implement an async method of an interface you cannot change.
The method execution takes for a long time because it is CPU bound: now you can use a thread. But I typically would not use pool threads for long lasting tasks as it can cause nasty side effects if the thread pool is out of threads. Use await Task.Factory.StartNew(() => MyLongRunningTask(), cancellationToken, TaskCreationOptions.LongRunning); instead, which creates a brand new thread instead of bothering the pool.
The method execution takes for a long time because it is IO bound (eg. sending/receiving packets via a hardware): Use TaskCompletitionSource<T>, add a hook to the whatever completition event of the device (eg. OS hook or IRQ notification) and from that set the result of the completition source and return its task.
Ok, so basically I have a bunch of tasks (10) and I want to start them all at the same time and wait for them to complete. When completed I want to execute other tasks. I read a bunch of resources about this but I can't get it right for my particular case...
Here is what I currently have (code has been simplified):
public async Task RunTasks()
{
var tasks = new List<Task>
{
new Task(async () => await DoWork()),
//and so on with the other 9 similar tasks
}
Parallel.ForEach(tasks, task =>
{
task.Start();
});
Task.WhenAll(tasks).ContinueWith(done =>
{
//Run the other tasks
});
}
//This function perform some I/O operations
public async Task DoWork()
{
var results = await GetDataFromDatabaseAsync();
foreach (var result in results)
{
await ReadFromNetwork(result.Url);
}
}
So my problem is that when I'm waiting for tasks to complete with the WhenAll call, it tells me that all tasks are over even though none of them are completed. I tried adding Console.WriteLine in my foreach and when I have entered the continuation task, data keeps coming in from my previous Tasks that aren't really finished.
What am I doing wrong here?
You should almost never use the Task constructor directly. In your case that task only fires the actual task that you can't wait for.
You can simply call DoWork and get back a task, store it in a list and wait for all the tasks to complete. Meaning:
tasks.Add(DoWork());
// ...
await Task.WhenAll(tasks);
However, async methods run synchronously until the first await on an uncompleted task is reached. If you worry about that part taking too long then use Task.Run to offload it to another ThreadPool thread and then store that task in the list:
tasks.Add(Task.Run(() => DoWork()));
// ...
await Task.WhenAll(tasks);
If you want to run those task's parallel in different threads using TPL you may need something like this:
public async Task RunTasks()
{
var tasks = new List<Func<Task>>
{
DoWork,
//...
};
await Task.WhenAll(tasks.AsParallel().Select(async task => await task()));
//Run the other tasks
}
These approach parallelizing only small amount of code: the queueing of the method to the thread pool and the return of an uncompleted Task. Also for such small amount of task parallelizing can take more time than just running asynchronously. This could make sense only if your tasks do some longer (synchronous) work before their first await.
For most cases better way will be:
public async Task RunTasks()
{
await Task.WhenAll(new []
{
DoWork(),
//...
});
//Run the other tasks
}
To my opinion in your code:
You should not wrap your code in Task before passing to Parallel.ForEach.
You can just await Task.WhenAll instead of using ContinueWith.
Essentially you're mixing two incompatible async paradigms; i.e. Parallel.ForEach() and async-await.
For what you want, do one or the other. E.g. you can just use Parallel.For[Each]() and drop the async-await altogether. Parallel.For[Each]() will only return when all the parallel tasks are complete, and you can then move onto the other tasks.
The code has some other issues too:
you mark the method async but don't await in it (the await you do have is in the delegate, not the method);
you almost certainly want .ConfigureAwait(false) on your awaits, especially if you aren't trying to use the results immediately in a UI thread.
The DoWork method is an asynchronous I/O method. It means that you don't need multiple threads to execute several of them, as most of the time the method will asynchronously wait for the I/O to complete. One thread is enough to do that.
public async Task RunTasks()
{
var tasks = new List<Task>
{
DoWork(),
//and so on with the other 9 similar tasks
};
await Task.WhenAll(tasks);
//Run the other tasks
}
You should almost never use the Task constructor to create a new task. To create an asynchronous I/O task, simply call the async method. To create a task that will be executed on a thread pool thread, use Task.Run. You can read this article for a detailed explanation of Task.Run and other options of creating tasks.
Just also add a try-catch block around the Task.WhenAll
NB: An instance of System.AggregateException is thrown that acts as a wrapper around one or more exceptions that have occurred. This is important for methods that coordinate multiple tasks like Task.WaitAll() and Task.WaitAny() so the AggregateException is able to wrap all the exceptions within the running tasks that have occurred.
try
{
Task.WaitAll(tasks.ToArray());
}
catch(AggregateException ex)
{
foreach (Exception inner in ex.InnerExceptions)
{
Console.WriteLine(String.Format("Exception type {0} from {1}", inner.GetType(), inner.Source));
}
}
I'm not sure how I'm supposed to mix plinq and async-await. Suppose that I have the following interface
public interface IDoSomething (
Task Do();
}
I have a list of these which I would like to execute in parallel and be able to await the completion of all.
public async Task DoAll(IDoSomething[] doers) {
//Execute all doers in parallel ideally using plinq and
//continue when all are complete
}
How to implement this? I'm not sure how to go from parallel linq to Tasks and vice versa.
I'm not terribly worried about exception handling. Ideally the first one would fire and break the whole process as I plan to discard the entire thing on error.
Edit: A lot of people are saying Task.WaitAll. I'm aware of this but my understanding (unless someone can demonstrate otherwise) is that it won't actively parallelize things for you to multiple available processor cores. What I'm specifically asking is twofold -
if I await a Task within a Plinq Action does that get rid of a lot of the advantage since it schedules a new thread?
If I doers.AsParallel().ForAll(async d => await d.Do()) which takes about 5 second on average, how do I not spin the invoking thread in the meantime?
What you're looking for is this:
public Task DoAllAsync(IEnumerable<IDoSomething> doers)
{
return Task.WhenAll(doers.Select(doer => Task.Run(() => doer.Do())));
}
Using Task.Run will use a ThreadPool thread to execute each synchronous part of the async method Do in parallel while Task.WhenAll asynchronously waits for the asynchronous parts together that are executing concurrently.
This is a good idea only if you have substantial synchronous parts in these async methods (i.e. the parts before an await) for example:
async Task Do()
{
for (int i = 0; i < 10000; i++)
{
Math.Pow(i,i);
}
await Task.Delay(10000);
}
Otherwise, there's no need for parallelism and you can just fire the asynchronous operations concurrently and wait for all the returned tasks using Task.WhenAll:
public Task DoAllAsync(IEnumerable<IDoSomething> doers)
{
return Task.WhenAll(doers.Select(doer => doer.Do()));
}
public async Task DoAll(IDoSomething[] doers) {
//using ToArray to materialize the query right here
//so we don't accidentally run it twice later.
var tasks = doers.Select(d => Task.Run(()=>d.Do())).ToArray();
await Task.WhenAll(tasks);
}
In the example below two await calls are used. To gain performance, the sample gets converted Task.WaitAll() instead (not really any faster, but this is just an example).
This is code from a library using Sqlite.Net on Android and the method gets called from OnResume() on the main UI thread:
public async Task SetupDatabaseAsync()
{
await CreateTableAsync<Session>();
await CreateTableAsync<Speaker>();
}
Here's the alternative:
public void SetupDatabaseAsync()
{
var t1 = CreateTableAsync<Session>();
var t2 = CreateTableAsync<Speaker>();
Task.WaitAll(t1, t2);
}
But from my understanding Task.WaitAll() should block the UI thread while waiting, thus leading to a deadlock. But it works just fine. Is that because the two calls don't actually invoke anything on the UI thread?
What's the difference if I use Task.WhenAll() instead? My guess it that it would work even if the UI thread would be invoked, just like with await.
I describe the details of the deadlock situation on my blog. I also have an MSDN article on SynchronizationContext that you may find helpful.
In summary, Task.WaitAll will deadlock in your scenario, but only if the tasks need to sync back to the UI thread in order to complete. You can conclude that CreateTableAsync<T>() does not sync back to the UI thread.
In contrast, this code will deadlock:
public async Task SetupDatabaseAsync()
{
await CreateTableAsync<Session>();
await CreateTableAsync<Speaker>();
}
Task.WaitAll(SetupDatabaseAsync());
I recommend that you not block on asynchronous code; in the async world, sync'ing back to the context is the default behavior (as I describe in my async intro), so it's easy to accidentally do it. Some changes to Sqlite.Net in the future may (accidentally) sync back to the original context, and then any code using Task.WaitAll like your original example will suddenly deadlock.
It's best to use async "all the way":
public Task SetupDatabaseAsync()
{
var t1 = CreateTableAsync<Session>();
var t2 = CreateTableAsync<Speaker>();
return Task.WhenAll(t1, t2);
}
"Async all the way" is one of the guidelines I recommend in my asynchronous best practices article.
When you're blocking the UI thread (and the current synchronization context) it will only cause a deadlock if one of the tasks that you're waiting on marshals a delegate to the current context and then waits on it (synchronously or asynchronously). Synchronously blocking on any async method isn't an instant deadlock in every single case.
Because async methods will, by default, marshal the remainder of the method to the current synchronization context and after every single await, and because the task will never finish until that happens, it means that synchronously waiting on methods that use async/await will often deadlock; at least unless the described behavior is explicitly overridden (through, say ConfigureAwait(false)).
Using WhenAll means that you're not blocking the current synchronization context. Instead of blocking the thread you're just scheduling another continuation to be run when all of the other tasks finish, leaving the context free to handle any other requests that are ready right now (like, say, the continuation from the underlying async method that WhenAll is waiting on).
Maybe this sample will demonstrate what might be happening. It's an iOS view loading. Try it with both the await call and without it (commented out below). Without any await in the function it will run synchronously and the UI will be blocked.
public async override void ViewDidLoad()
{
base.ViewDidLoad ();
var d1 = Task.Delay (10);
var d2 = Task.Delay (10000);
//await Task.Delay (10);
Task.WaitAll (d1, d2);
this.label.Text = "Tasks have ended - really!";
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear (animated);
this.label.Text = "Tasks have ended - or have they?";
}