Please know that I'm aware that Parallel.Invoke() is meant for task synchronization. My question is this:
Is there a way to call an anonymous method using something like Parallel.Invoke in which the call does NOT wait on the execution to finish?
I thought the whole point of parallel execution (or parallel invokation) is to NOT have to wait for the task to finish. If you want to wait for a piece of code to finish executing, instead of using Parallel.Invoke, why not just call the code directly? I guess I just don't understand the point of Parallel.Invoke. The documentation just says what it does, but doesn't mention any use-cases when this would be more useful than just calling the code directly.
If you want to wait for a piece of code to finish executing, instead of using Parallel.Invoke, why not just call the code directly?
Well normally you'd call Parallel.Invoke with multiple pieces of work. If you execute those pieces of work in series, it'll (probably) take longer than executing them in parallel.
"Execute in parallel" isn't the same as "execute in the background" - you appear to be looking for the latter, but that's not what Parallel.Invoke is about.
If you just want to start tasks, use Task.Run (or Task.Factory.StartNew prior to .NET 4.5). Parallel.Invoke is specifically for executing a bunch of actions in parallel, but then waiting for those parallel actions to complete.
As a concrete example, you can perform a sort by partitioning, then recursively sorting both sides of the pivot in parallel. Doing this will make use of multiple cores, but you would usually still want to wait until that whole sort had completed before you proceed.
Simply wrap your Parallel.Invoke call in a Task if you don't want to wait for completion.
Task.Factory.StartNew( () =>
{
Parallel.Invoke( <one or more actions> );
} );
Are you looking for something like this?
async Task ParallelInvokeAsync(Action[] actions)
{
var tasks = actions.Select(a => Task.Run(a));
await Task.WhenAll(tasks);
}
Background execution:
ParallelInvokeAsync(actions);
MessageBox.Show("I'm working");
Background execution with blocking, very similar to Parallel.Invoke:
ParallelInvokeAsync(actions).Wait();
MessageBox.Show("I'm dome working");
Related
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?
I'm currently getting into the async/await keywords, and went through the following questions: When correctly use Task.Run and when just async-await and Async/Await vs Threads
However even the second link doesn't answer my question, which is when to simply use
Task.Run(...)
versus
await Task.Run(...)
Is it situational or is there something to be gained by using await (and thus returning to the caller)?
The code Task.Run(...) (in both examples) sends a delegate to the thread pool and returns a task that will contain the results of that delegate. These "results" can be an actual return value, or it can be an exception. You can use the returned task to detect when the results are available (i.e., when the delegate has completed).
So, you should make use of the Task if any of the following are true:
You need to detect when the operation completed and respond in some way.
You need to know if the operation completed successfully.
You need to handle exceptions from the operation.
You need to do something with the return value of the operation.
If your calling code needs to do any of those, then use await:
await Task.Run(...);
With long-running background tasks, sometimes you want to do those (e.g., detect exceptions), but you don't want to do it right away; in this case, just save the Task and then await it at some other point in your application:
this.myBackgroundTask = Task.Run(...);
If you don't need any of the above, then you can do a "fire and forget", as such:
var _ = Task.Run(...); // or just "Task.Run(...);"
Note that true "fire and forget" applications are extremely rare. It's literally saying "run this code, but I don't care whether it completes, when it completes, or whether it was successful".
You can use Task.Run() when handling logic with fire and forget type, similar to invoking events if someone is subscribed to them. You can use this for logging, notifying, etc.
If you depend of the result or actions executed in your method, you need to use await Task.Run() as it pauses current execution until your task is finished.
What is the difference when using await on multiple await task vs waiting on all the tasks to finish. My under standing is the scenario 2 is better in terms of performance because both asyncTask1 and asyncTask2 are preformed in parallel.
scenario 1 :
async Task Task()
{
await asyncTask1();
await asyncTask2();
}
scenario 2 :
async Task Task()
{
t1 = asyncTask1();
t2 = asyncTask2();
await Task.WhenAll(createWorkflowtask, getTaskWorkflowTask);
}
In scenario 1, tasks are run sequentially (asyncTask1 must complete before asyncTask2 starts) while in scenario 2 the two tasks can run in parallel.
You wrote: "... because both asyncTask1 and asyncTask2 are preformed in parallel."
No they are not!
Addition: Below I wrote that everything in async-await is performed by one thread. Schneider commented correctly that in async-await multiple threads can be involved. See the addition at the end.
An article that helped me a lot to understand how async-await works was this interview with Eric-Lippert who compared async/await with a cook making dinner. (Somewhere half-way, search for async-await).
Eric Lippert explains that if a cook starts doing something and finds after a while that he has nothing else to do but wait for a process to finish, this cook looks around to see if he can do something else instead of waiting.
When using async/await, there is still one thread involved. This thread can do only one thing at a time. While the thread is busy doing Task1, it can't execute Task2. Only if it finds an await in Task1, it will start executing statements from Task2. In your scenario 2 the tasks are not executed in parallel.
However there is a difference between the scenarios. In scenario 1 the first statement of task2 will not be executed before task1 completely finishes. Scenario 2 will start executing the first statements of task2 as soon as task1 encounters an await.
If you really want task2 to do something while task1 is also doing something, you'll have to start doing task2 in a separate thread. The easy method to do this in your scenario would be:
var task1 = Task.Run( () => asyncTask1())
// this statement is executed while task1 begins executing on a different thread.
// hence this thread is free to do other things, like performing statements
// from task2:
var task2 = asyncTask();
// the following statement will only be executed if task2 encounters an await
DoSomethingElse();
// when we need results from both task1 and task2:
await Task.WhenAll(new Task[] {task1, task2});
So usually, it is best only to await for a task to finish if you need the result of this task. As long as you can do other things, do these other things, they will be executed as soon as the other task starts awaiting until you start awaiting, in which case your caller will start doing things until his await etc.
The advantage of this method above doing things in parallel are manyfold:
Everything is performed by one thread: no need of mutexes, no chance of deadlock, starvation, etc
Your code looks quite sequential. Compare this with code that uses Task.ContinueWith and similar statements
There is no overhead of starting a separate thread / running a thread from the thread pool
Addition: Schneider's comment below about several threads is correct.
Some testing showed me that the thread ID of the current thread in the awaitable tasks is different than the thread ID of the calling thread.
For newbees to async-await it is important to understand that although various threads are involved, async-await does NOT mean that the tasks are performed in parallel. If you want parallelism you specifically have to say that the task must be run in parallel.
It seems that the cook in Eric Lippert's analogy is in fact a team of cooks, who constantly look around to see if they can help some of the other cooks instead of waiting for their tasks to finish. And indeed if cook Albert sees an await and starts doing something else, cook Bernard might finish the task of cook Albert.
In the first scenario you launch a task and then wait until is completed, then pass to the second one and wait until finish before exit from the method.
In the second scenario you launch the two task in parallel and then wait until tgey are completed when you call Task.WhenAll
Using Task.WhenAll
You cannot use methods with return types unless all of return types are the same and using generic version of WhenAll method
You don't have control over sequences that methods executed because these methods is executing in parallel
Unhandled exception in one method doesn't break the execution of other methods(because of parallel nature)
From MSDN
If any of the supplied tasks completes in a faulted state, the returned task will also complete in a TaskStatus.Faulted state, where its exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied tasks.
Using await on multiple methods
You have control over sequences that functions called
You can use different return types and use that return types on next steps
Unhandled exception in one method will break the execution of other methods
What would be an appropriate way to re-write my SlowMethodAsync async method, which executes a long running task, that can be awaited, but without using Task.Run?
I can do it with Task.Run as following:
public async Task SlowMethodAsync()
{
await Task.Run(() => SlowMethod());
}
public void SlowMethod()
{
//heavy math calculation process takes place here
}
The code, as it shown above, will spawn a new thread from a thread-pool. If it can be done differently, will it run on the invocation thread, and block it any way, as the SlowMethod content is a solid chunk of math processing without any sort of yielding and time-slice surrendering.
Just to clarify that I need my method to stay asynchronous, as it unblocks my UI thread. Just looking for another possible way to do that in a different way to how it's currently done, while keeping async method signature.
async methods are meant for asynchronous operations. They enable not blocking threads for non-CPU-bound work. If your SlowMethod has any IO-bound operations which are currently executed synchronously (e.g. Stream.Read or Socket.Send) you can exchange these for async ones and await them in your async method.
In your case (math processing) the code's probably mostly CPU-bound, so other than offloading the work to a ThreadPool thread (using Task.Run) there's no reason to use async as all. Keep SlowMethod as it is and it will run on the calling thread.
Regarding your update: You definitely want to use Task.Run (or one of the Task.Factory.StartNew overloads) to offload your work to a different thread.
Actually, for your specific case, you should use
await Task.Factory.StartNew(() => SlowMethod(), TaskCreationOptions.LongRunning)
which will allow the scheduler to run your synchronous task in the appropriate place (probably in a new thread) so it doesn't gum up the ThreadPool (which isn't really designed for CPU heavy workloads).
Wouldn't it be better just to call SlowMethod synchronously? What are you gaining by awaiting it?
I'm using TPL in my current project and using Parallel.Foreach to spin many threads. The Task class contains Wait() to wait till the task gets completed. Like that, how I can wait for the Parallel.ForEach to complete and then go into executing next statements?
You don't have to do anything special, Parallel.Foreach() will wait until all its branched tasks are complete. From the calling thread you can treat it as a single synchronous statement and for instance wrap it inside a try/catch.
Update:
The old Parallel class methods are not a good fit for async (Task based) programming. But starting with dotnet 6 we can use Parallel.ForEachAsync()
await Parallel.ForEachAsync(items, (item, cancellationToken) =>
{
await ...
});
There are a few overloads available and the 'body' method should return a ValueTask.
You don't need that with Parallel.Foreach: it only executes the foreach in as many thread as there are processors available, but it returns synchronously.
More information can be found here
As everyone here said - you dont need to wait for it. What I can add from my experience:
If you have an async body to execute and you await some async calls inside, it just ran through my code and did not wait for anything. So I just replaced the await with .Result - then it worked as intended. I couldnt find out though why is that so :/
if you are storing results from the tasks in a List, make sure to use a thread-safe data structure such as ConcurrentBag, otherwise, some results would be missing because of concurrent write issues.
I believe that you can use IsCompleted like follows:
if(Parallel.ForEach(files, f => ProcessFiles(f)).IsCompleted)
{
// DO STUFF
}