The different use of Task Parallel library - c#

I saw few people call function using syntax like:
Parallel.Invoke(() => Method1(yourString1),() => Method2(youString2));
And few people write code like:
Task myFirstTask = Task.Factory.StartNew(() => Method1(5));
Task mySecondTask = Task.Factory.StartNew(() => Method2("Hello"));
So my question is when one should use Parallel.Invoke() and when one should create instance of Task class and call StartNew() method.
Parallel.Invoke() looks very handy.so what is the significance of using Task class & StartNew() method.........put some light and tell me the importance of different approach for same kind of job means call two function parallel with two different syntax.
i never use before the Task Parallel library. so there could be some hidden reason for using two approach for calling function. please guide me in detail. thanks

Well, Parallel.Invoke will block until both of the new tasks have completed.
The second approach will start two new tasks, but not wait for them to be completed. You could await them manually, or in C# 5 the new async/await feature will help you "wait" asynchronously.
It really depends what you want to do. If you want your thread to block until all the tasks have finished, Parallel.Invoke is handy.

Related

Running async functions in parallel from list of interfaces

I have a similair question to Running async methods in parallel in that I wish to run a number of functions from a list of functions in parallel.
I have noted in a number of comments online it is mentioned that if you have another await in your methods, Task.WhenAll() will not help as Async methods are not parallel.
I then went ahead and created a thread for each using function call with the below (the number of parallel functions will be small typically 1 to 5):
public interface IChannel
{
Task SendAsync(IMessage message);
}
public class SendingChannelCollection
{
protected List<IChannel> _channels = new List<IChannel>();
/* snip methods to add channels to list etc */
public async Task SendAsync(IMessage message)
{
var tasks = SendAll(message);
await Task.WhenAll(tasks.AsParallel().Select(async task => await task));
}
private IEnumerable<Task> SendAll(IMessage message)
{
foreach (var channel in _channels)
yield return channel.SendAsync(message, qos);
}
}
I would like to double check I am not doing anything horrendous with code smells or bugs as i get to grips with what I have patched together from what i have found online. Many thanks in advance.
Let's compare the behaviour of your line:
await Task.WhenAll(tasks.AsParallel().Select(async task => await task));
in contrast with:
await Task.WhenAll(tasks);
What are you delegating to PLINQ in the first case? Only the await operation, which does basically nothing - it invokes the async/await machinery to wait for one task. So you're setting up a PLINQ query that does all the heavy work of partitioning and merging the results of an operation that amounts to "do nothing until this task completes". I doubt that is what you want.
If you have another await in your methods, Task.WhenAll() will not help as Async methods are not parallel.
I couldn't find that in any of the answers to the linked questions, except for one comment under the question itself. I'd say that it's probably a misconception, stemming from the fact that async/await doesn't magically turn your code into concurrent code. But, assuming you're in an environment without a custom SynchronizationContext (so not an ASP or WPF app), continuations to async functions will be scheduled on the thread pool and possibly run in parallel. I'll delegate you to this answer to shed some light on that. That basically means that if your SendAsync looks something like this:
Task SendAsync(IMessage message)
{
// Synchronous initialization code.
await something;
// Continuation code.
}
Then:
The first part before await runs synchronously. If this part is heavyweight, you should introduce parallelism in SendAll so that the initialization code is run in parallel.
await works as usual, waiting for work to complete without using up any threads.
The continuation code will be scheduled on the thread pool, so if a few awaits finish up at the same time their continuations might be run in parallel if there's enough threads in the thread pool.
All of the above is assuming that await something actually awaits asynchronously. If there's a chance that await something completes synchronously, then the continuation code will also run synchronously.
Now there is a catch. In the question you linked one of the answers states:
Task.WhenAll() has a tendency to become unperformant with large scale/amount of tasks firing simultaneously - without moderation/throttling.
Now I don't know if that's true, since I weren't able to find any other source claiming that. I guess it's possible and in that case it might actually be beneficial to invoke PLINQ to deal with partitioning and throttling for you. However, you said you typically handle 1-5 functions, so you shouldn't worry about this.
So to summarize, parallelism is hard and the correct approach depends on how exactly your SendAsync method looks like. If it has heavyweight initialization code and that's what you want to parallelise, you should run all the calls to SendAsync in parallel. Otherwise, async/await will be implicitly using the thread pool anyway, so your call to PLINQ is redundant.

Task.WhenAll and task starting behaviour

I've got a fairly simple application using Task.WhenAll. The issue I am facing so far is that I don't know if I should start the subtasks myself or let WhenAll start them as appropriate.
The examples online show using tasks from framework methods, where it's not clear to me if the tasks returned have already started or not. However I've created my own tasks with an Action, so it's a detail that I have to address.
When I'm using Task.WhenAll, should I start the constituent tasks directly, or should I let Task.WhenAll handle it for fun, profit, and improved execution speed?
For further fun, the subtasks contain lots of blocking I/O.
WhenAll won't start tasks for you. You have to start them yourself.
var unstartedTask = new Task(() => {});
await Task.WhenAll(unstartedTask); // this task won't complete until unstartedTask.Start()
However, generally, tasks created (e.g. using Task.Run, async methods, etc.) have already been started. So you generally don't have to take a separate action to start the task.
var task = Task.Run(() => {});
await Task.WhenAll(task); // no need for task.Start()
I've created my own tasks with an Action
When you're working with asynchronous tasks, the convention is to only deal with tasks already in progress. So using the Task constructor and Start is inappropriate; it would be better to use Task.Run.
As others have noted, Task.WhenAll only aggregates the tasks; it does not start them for you.
Task.WhenAll(IEnumerable) will handle the supplied tasks for you, but you can create them using the most common way - by executing Task.Run(Action) or TaskFactory.StartNew(Action) method.
Just for a note: if any of the tasks is completed in Faulted state, resulting task will complete in Faulted state as well, having AggregateException set to its Exception property.

How to execute nested async/await code in parallel while maintaining the same thread on await continuations?

This might be the worst StackOverflow title I've ever written. What I'm actually trying to do is execute an asynchronous method that uses the async/await convention (and itself contains additional await calls) from within a synchronous method multiple times in parallel while maintaining the same thread throughout the execution of each branch of the parallel execution, including for all await continuations. To put it another way, I want to execute some async code synchronously, but I want to do it multiple times in parallel. Now you can see why the title was so bad. Perhaps this is best illustrated with some code...
Assume I have the following:
public class MyAsyncCode
{
async Task MethodA()
{
// Do some stuff...
await MethodB();
// Some other stuff
}
async Task MethodB()
{
// Do some stuff...
await MethodC();
// Some other stuff
}
async Task MethodC()
{
// Do some stuff...
}
}
The caller is synchronous (from a console application). Let me try illustrating what I'm trying to do with an attempt to use Task.WaitAll(...) and wrapper tasks:
public void MyCallingMethod()
{
List<Task> tasks = new List<Task>();
for(int c = 0 ; c < 4 ; c++)
{
MyAsyncCode asyncCode = new MyAsyncCode();
tasks.Add(Task.Run(() => asyncCode.MethodA()));
}
Task.WaitAll(tasks.ToArray());
}
The desired behavior is for MethodA, MethodB, and MethodC to all be run on the same thread, both before and after the continuation, and for this to happen 4 times in parallel on 4 different threads. To put it yet another way, I want to remove the asynchronous behavior of my await calls since I'm making the calls parallel from the caller.
Now, before I go any further, I do understand that there's a difference between asynchronous code and parallel/multi-threaded code and that the former doesn't imply or suggest the latter. I'm also aware the easiest way to achieve this behavior is to remove the async/await declarations. Unfortunately, I don't have the option to do this (it's in a library) and there are reasons why I need the continuations to all be on the same thread (having to do with poor design of said library). But even more than that, this has piqued my interest and now I want to know from an academic perspective.
I've attempted to run this using PLINQ and immediate task execution with .AsParallel().Select(x => x.MethodA().Result). I've also attempted to use the AsyncHelper class found here and there, which really just uses .Unwrap().GetAwaiter().GetResult(). I've also tried some other stuff and I can't seem to get the desired behavior. I either end up with all the calls on the same thread (which obviously isn't parallel) or end up with the continuations executing on different threads.
Is what I'm trying to do even possible, or are async/await and the TPL just too different (despite both being based on Tasks)?
The methods that you are calling do not use ConfigureAwait(false). This means that we can force the continuations to resume in a context we like. Options:
Install a single-threaded synchronization context. I believe Nito.Async has that.
Use a custom TaskScheduler. await looks at TaskScheduler.Current and resumes at that scheduler if it is non-default.
I'm not sure if there are any pros and cons for either option. Option 2 has easier scoping I think. Option 2 would look like:
Task.Factory.StartNew(
() => MethodA()
, new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler).Unwrap();
Call this once for each parallel invocation and use Task.WaitAll to join all those tasks. Probably you should dispose of that scheduler as well.
I'm (ab)using ConcurrentExclusiveSchedulerPair here to get a single-threaded scheduler.
If those methods are not particularly CPU-intensive you can just use the same scheduler/thread for all of them.
You can create 4 independent threads, each one executes MethodA with a limited-concurrency (actually, no concurrency at all) TaskScheduler. That will ensure that every Task, and continuation Tasks, that the thread creates, will be executed by that thread.
public void MyCallingMethod()
{
CancellationToken csl = new CancellationToken();
var threads = Enumerable.Range(0, 4).Select(p =>
{
var t = new Thread(_ =>
{
Task.Factory.StartNew(() => MethodA(), csl, TaskCreationOptions.None,
new LimitedConcurrencyLevelTaskScheduler(1)).Wait();
});
t.Start();
return t;
}).ToArray();
//You can block the main thread and wait for the other threads here...
}
That won't ensure you a 4th degree parallelism, of course.
You can see an implementation of such TaskScheduler in MSDN - https://msdn.microsoft.com/en-us/library/ee789351(v=vs.110).aspx

await/async and going outside the box

I have a question regarding await/async and using async methods in slightly different scenarios than expected, for example not directly awaiting them. For example, Lets say I have two routines I need to complete in parallel where both are async methods (they have awaits inside). I am using await TAsk.WhenAll(...) which in turn expects some sort of list of tasks to wait for. What I did is something like this:
await Task.WhenAll(new Task[]
{
Task.Run(async () => await internalLoadAllEmailTargets()),
Task.Run(async () => await internalEnumerateInvoices())
});
This seems overly elaborate to me, in the sense that I am creating async tasks whose sole purpose is to invoke another task. Can't I just use tasks which are returned from the async method state engine? Yet, I am failing to do that since compiler treats every direct mention of async method as an invocation point:
// this doesn't seem to work ok
await Task.WhenAll(new Task[]
{
internalLoadAllEmailTargets(),
internalEnumerateInvoices()
});
If its like this, it seems to synchronously calls one after another, and if I place await in front of methods, it is no longer a Task. Is there some rule book on how async methods should be handled outside plain await?
Every async method starts executing synchronously, but when it hits its first await, it may behave asynchronously. So this line:
await Task.WhenAll(internalLoadAllEmailTargetsAsync(), internalEnumerateInvoicesAsync());
should work just fine. It is roughly equivalent to this:
var _1 = internalLoadAllEmailTargetsAsync();
var _2 = internalEnumerateInvoicesAsync();
await Task.WhenAll(_1, _2);
If your methods are truly asynchronous, then this should be fine.
Now, if your methods are actually doing some synchronous work - say, heavy CPU-bound code - then you may want to use Task.Run to invoke them (if your calling code is on a UI thread).
You have some code, which creates Task object, and it will be invoked as usual, i.e synchronously. Control will be returned to the invoking code only after Task creation and in case of async it will be after the first await.
So, if it's a problem, that some part of your method will be invoked in blocking manner, you could use Task.Yield at the beginning, just be careful with SynchronizationContext and thread switches.
But in most cases there is nothing wrong with that scenario, because code, which creates Task, is small and fast, while actual timing is caused by some sort of IO operation.

Task.Run vs. direct async call for starting long-running async methods

Several times, I have found myself writing long-running async methods for things like polling loops. These methods might look something like this:
private async Task PollLoop()
{
while (this.KeepPolling)
{
var response = await someHttpClient.GetAsync(...).ConfigureAwait(false);
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
// do something with content
await Task.Delay(timeBetweenPolls).ConfigureAwait(false);
}
}
The goal of using async for this purpose is that we don't need a dedicated polling thread and yet the logic is (to me) easier to understand than using something like a timer directly (also, no need to worry about reentrance).
My question is, what is the preferred method for launching such a loop from a synchronous context? I can think of at least 2 approaches:
var pollingTask = Task.Run(async () => await this.PollLoop());
// or
var pollingTask = this.PollLoop();
In either case, I can respond to exceptions using ContinueWith(). My main understanding of the difference between these two methods is that the first will initially start looping on a thread-pool thread, whereas the second will run on the current thread until the first await. Is this true? Are there other things to consider or better approaches to try?
My main understanding of the difference between these two methods is
that the first will initially start looping on a thread-pool thread,
whereas the second will run on the current thread until the first
await. Is this true?
Yes. An async method returns its task to its caller on the first await of an awaitable that is not already completed.
By convention most async methods return very quickly. Yours does as well because await someHttpClient.GetAsync will be reached very quickly.
There is no point in moving the beginning of this async method onto the thread-pool. It adds overhead and saves almost no latency. It certainly does not help throughput or scaling behavior.
Using an async lambda here (Task.Run(async () => await this.PollLoop())) is especially useless. It just wraps the task returned by PollLoop with another layer of tasks. it would be better to say Task.Run(() => this.PollLoop()).
My main understanding of the difference between these two methods is that the first will initially start looping on a thread-pool thread, whereas the second will run on the current thread until the first await. Is this true?
Yes, that's true.
In your scenario, there seem to be no need for using Task.Run though, there's practically no code between the method call and the first await, and so PollLoop() will return almost immediately. Needlessly wrapping a task in another task only makes the code less readable and adds overhead. I would rather use the second approach.
Regarding other considerations (e.g. exception handling), I think the two approaches are equivalent.
The goal of using async for this purpose is that we don't need a dedicated polling thread and yet the logic is (to me) easier to understand than using something like a timer directly
As a side-note, this is more or less what a timer would do anyway. In fact Task.Delay is implemented using a timer!

Categories