I have sample code to compare processing time for Parallel approach and Task approach. The goal of this experiment is understanding of how do they work.
So my questions are:
Why Parallel worked faster then Task?
Do my results mean that I should use Parallel instead of Task?
Where should I use Task and where Parallel?
What benefits of using Task in comparison to Parallel?
Does Task is just a wrap for ThreadPool.QueueUserWorkItem method?
public Task SomeLongOperation()
{
return Task.Delay(3000);
}
static void Main(string[] args)
{
Program p = new Program();
List<Task> tasks = new List<Task>();
tasks.Add(Task.Factory.StartNew(() => p.SomeLongOperation()));
tasks.Add(Task.Factory.StartNew(() => p.SomeLongOperation()));
var arr = tasks.ToArray();
Stopwatch sw = Stopwatch.StartNew();
Task.WaitAll(arr);
Console.WriteLine("Task wait all results: " + sw.Elapsed);
sw.Stop();
sw = Stopwatch.StartNew();
Parallel.Invoke(() => p.SomeLongOperation(), () => p.SomeLongOperation());
Console.WriteLine("Parallel invoke results: " + sw.Elapsed);
sw.Stop();
Console.ReadKey();
}
Here are my processing results:
EDIT:
Changed code to look like this:
Program p = new Program();
Task[] tasks = new Task[2];
Stopwatch sw = Stopwatch.StartNew();
tasks[0] = Task.Factory.StartNew(() => p.SomeLongOperation());
tasks[1] = Task.Factory.StartNew(() => p.SomeLongOperation());
Task.WaitAll(tasks);
Console.WriteLine("Task wait all results: " + sw.Elapsed);
sw.Stop();
sw = Stopwatch.StartNew();
Parallel.Invoke(() => p.SomeLongOperation(), () => p.SomeLongOperation());
Console.WriteLine("Parallel invoke results: " + sw.Elapsed);
sw.Stop();
My new results:
EDIT 2:
When I replaced code with Parallel.Invoke to be first and Task.WaitAll to be second the situation has been changed cardinally. Now Parallel is slower. It makes me think of incorrectness of my estimates. I changed code to look like this:
Program p = new Program();
Task[] tasks = new Task[2];
Stopwatch sw = null;
for (int i = 0; i < 10; i++)
{
sw = Stopwatch.StartNew();
Parallel.Invoke(() => p.SomeLongOperation(), () => p.SomeLongOperation());
string res = sw.Elapsed.ToString();
Console.WriteLine("Parallel invoke results: " + res);
sw.Stop();
}
for (int i = 0; i < 10; i++)
{
sw = Stopwatch.StartNew();
tasks[0] = Task.Factory.StartNew(() => p.SomeLongOperation());
tasks[1] = Task.Factory.StartNew(() => p.SomeLongOperation());
Task.WaitAll(tasks);
string res2 = sw.Elapsed.ToString();
Console.WriteLine("Task wait all results: " + res2);
sw.Stop();
}
And here are my new results:
Now I can suggest that this experiment is much more clear. The results are almost the same. Sometimes Parallel and sometimes Task is faster. Now my questions are:
1. Where should I use Task and where Parallel?
2. What benefits of using Task in comparison to Parallel?
3. Does Task is just a wrap for ThreadPool.QueueUserWorkItem method?
Any helpful info that can clarify those questions are welcome.
EDIT as of this article from MSDN:
Both Parallel and Task are wrappers for ThreadPool. Parallel invoke also awaits until all tasks will be finished.
Related to your questions:
Using Task, Parallel or ThreadPool depends on the granularity of control you need to have on the execution of your parallel tasks. I'm personally got used to Task.Factory.StartNew(), but that's a personal opinion. The same relates to ThreadPool.QueueUserWorkItem()
Additional Information: The first call to Parallel.Invoke() and Task.Factory.StartNew() might be slower due to internal initialization.
If you start nongeneric Tasks(i.e. "void Tasks without a return value") and immediately Wait for them, use Parallel.Invoke instead. Your intent is immediately clear to the reader.
Use Tasks if:
you do not Wait immediately
you need return values
you need to give parameters to the methods called
you require TaskCreationOptions functionality
you require CancellationToken or TaskScheduler functionality and don't want to use ParallelOptions
basically, if you want more options or control
Yes, you can get around some of these, e.g. Parallel.Invoke(() => p.OpWithToken(CancellationToken) but that obfuscates your intent. Parallel.Invoke is for doing a bunch of work using as much CPU power as possible. It gets done, it doesn't deadlock, and you know this in advance.
Your testing is horrid though. The red flag would be that your long action is to wait 3000 milliseconds, yet your tests take less than a tenth of a millisecond.
Task.Factory.StartNew(() => p.SomeLongOperation());
StartNew takes an Action, and executes this in a new main Task. The action () => SomeLongOperation() creates a subtask Task. After this subtask is created (not completed), the call to SomeLongOperation() returns, and the Action is done. So the main Task is already completed after a tenth millisecond, while the two subtasks you have no reference to are still running in the background. The Parallel path also creates two subtasks, which it doesn't track at all, and returns.
The correct way would be tasks[0] = p.SomeLongOperation();, which assigns a running task to the array. Then WaitAll checks for the finishing of this task.
Related
I have three methods that I call to do some number crunching that are as follows
results.LeftFront.CalcAi();
results.RightFront.CalcAi();
results.RearSuspension.CalcAi(geom, vehDef.Geometry.LTa.TaStiffness, vehDef.Geometry.RTa.TaStiffness);
Each of the functions is independent of each other and can be computed in parallel with no dead locks.
What is the easiest way to compute these in parallel without the containing method finishing until all three are done?
See the TPL documentation. They list this sample:
Parallel.Invoke(() => DoSomeWork(), () => DoSomeOtherWork());
So in your case this should just work:
Parallel.Invoke(
() => results.LeftFront.CalcAi(),
() => results.RightFront.CalcAi(),
() => results.RearSuspension.CalcAi(geom,
vehDef.Geometry.LTa.TaStiffness,
vehDef.Geometry.RTa.TaStiffness));
EDIT: The call returns after all actions have finished executing. Invoke() is does not guarantee that they will indeed run in parallel, nor does it guarantee the order in which the actions execute.
You can do this with tasks too (nicer if you later need Cancellation or something like results)
var task1 = Task.Factory.StartNew(() => results.LeftFront.CalcAi());
var task2 = Task.Factory.StartNew(() => results.RightFront.CalcAi());
var task3 = Task.Factory.StartNew(() =>results.RearSuspension.CalcAi(geom,
vehDef.Geometry.LTa.TaStiffness,
vehDef.Geometry.RTa.TaStiffness));
Task.WaitAll(task1, task2, task3);
In .NET 4, Microsoft introduced the Task Parallel Library which was designed to handle this kind of problem, see Parallel Programming in the .NET Framework.
To run parallel methods which are independent of each other ThreadPool.QueueUserWorkItem can also be used. Here is the sample method-
public static void ExecuteParallel(params Action[] tasks)
{
// Initialize the reset events to keep track of completed threads
ManualResetEvent[] resetEvents = new ManualResetEvent[tasks.Length];
// Launch each method in it's own thread
for (int i = 0; i < tasks.Length; i++)
{
resetEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback((object index) =>
{
int taskIndex = (int)index;
// Execute the method
tasks[taskIndex]();
// Tell the calling thread that we're done
resetEvents[taskIndex].Set();
}), i);
}
// Wait for all threads to execute
WaitHandle.WaitAll(resetEvents);
}
More detail about this function can be found here:
http://newapputil.blogspot.in/2016/03/running-parallel-tasks-using.html
var task1 = SomeLongRunningTask();
var task2 = SomeOtherLongRunningTask();
await Task.WhenAll(task1, task2);
The benefit of this over Task.WaitAll is that this will release the thread and await the completion of the two tasks.
I have two tasks Job1 and Job2 and below is the code. First time I ran Job1 and Job2 in a sequence and got the stopwatch output as 844 milliseconds. Second time I commented sequential jobs and called parallel task processing and got the stopwatch result as 11352 milliseconds. My assumption/expectation was I should get the output as 422 (because 844/2) or somewhere near to it. But the result is totally opposite. I need to wait both the jobs to be completed and hence I put t1.Wait() and t2.Wait(); Please help me to process these two jobs in half of sequential processing. Please find my code below:
public ActionResult Index()
{
Stopwatch s = new Stopwatch();
s.Start();
//Execute 2 jobs in a sequence
Job1();
Job2();
//Execute 2 jobs in parallel
//var t1 = Task.Run(() => { Job1(); });
//var t2 = Task.Run(() => { Job2(); });
//t1.Wait();
//t2.Wait();
s.Stop();
Debug.WriteLine("ElapsedMilliseconds: " + s.ElapsedMilliseconds);
return View();
}
private void Job1()
{
for (int i = 0; i < 1000; i++)
{
Debug.WriteLine(i);
}
}
private void Job2()
{
for (int i = 2000; i < 3000; i++)
{
Debug.WriteLine(i);
}
}
Essentially your 2nd example is slower due to the overhead of Debug.WriteLine during concurrency.
You'd notice a big difference if you remove Debug.WriteLine (which calls OutputDebugString under the hood).
MSDN states:
Applications should send very minimal debug output and provide a way for the user to enable or disable its use. To provide more detailed tracing, see Event Tracing.
As Eran states here:
"if several threads call OutputDebugString concurrently, they will be synchronized".
There's no concurrency in your first example so that could be a reason why its faster.
Also you might want to consider moving to a single wait.
Change your code from this:
//Execute 2 jobs in parallel
var t1 = Task.Run(() => { Job1(); });
var t2 = Task.Run(() => { Job2(); });
t1.Wait();
t2.Wait();
...to this:
//Execute 2 jobs in parallel
var tasks = new List<Task>();
tasks.Add(Task.Run(() => { Job1(); }));
tasks.Add(Task.Run(() => { Job2(); }));
Task.WaitAll(tasks.ToArray());
To understand why Tasks have nothing to do with performance but more with responsiveness you should read up on
Context switching: https://en.wikipedia.org/wiki/Context_switch
The processor uses lots of cycles to switch to another thread
Mutexes: https://en.wikipedia.org/wiki/Mutual_exclusion
Every time you call Debug.WriteLine the Task waits until Debug.WriteLine in the other Task is done and performs a context switch.
Why does running a hundred async tasks take longer than running a hundred threads?
I have the following test class:
public class AsyncTests
{
public void TestMethod1()
{
var tasks = new List<Task>();
for (var i = 0; i < 100; i++)
{
var task = new Task(Action);
tasks.Add(task);
task.Start();
}
Task.WaitAll(tasks.ToArray());
}
public void TestMethod2()
{
var threads = new List<Thread>();
for (var i = 0; i < 100; i++)
{
var thread = new Thread(Action);
threads.Add(thread);
thread.Start();
}
foreach (var thread in threads)
{
thread.Join();
}
}
private void Action()
{
var task1 = LongRunningOperationAsync();
var task2 = LongRunningOperationAsync();
var task3 = LongRunningOperationAsync();
var task4 = LongRunningOperationAsync();
var task5 = LongRunningOperationAsync();
Task[] tasks = {task1, task2, task3, task4, task5};
Task.WaitAll(tasks);
}
public async Task<int> LongRunningOperationAsync()
{
var sw = Stopwatch.StartNew();
await Task.Delay(500);
Debug.WriteLine("Completed at {0}, took {1}ms", DateTime.Now, sw.Elapsed.TotalMilliseconds);
return 1;
}
}
As far as can tell, TestMethod1 and TestMethod2 should do exactly the same. One uses TPL, two uses plain vanilla threads. One takes 1:30 minutes, two takes 0.54 seconds.
Why?
The Action method is currently blocking with the use of Task.WaitAll(tasks). When using Task by default the ThreadPool will be used to execute, this means you are blocking the shared ThreadPool threads.
Try the following and you will see equivalent performance:
Add a non-blocking implementation of Action, we will call it ActionAsync
private Task ActionAsync()
{
var task1 = LongRunningOperationAsync();
var task2 = LongRunningOperationAsync();
var task3 = LongRunningOperationAsync();
var task4 = LongRunningOperationAsync();
var task5 = LongRunningOperationAsync();
Task[] tasks = {task1, task2, task3, task4, task5};
return Task.WhenAll(tasks);
}
Modify TestMethod1 to properly handle the new Task returning ActionAsync method
public void TestMethod1()
{
var tasks = new List<Task>();
for (var i = 0; i < 100; i++)
{
tasks.Add(Task.Run(new Func<Task>(ActionAsync)));
}
Task.WaitAll(tasks.ToArray());
}
The reason you were having slow performance is because the ThreadPool will "slowly" spawn new threads if required, if you are blocking the few threads it has available, you will encounter a noticeable slowdown. This is why the ThreadPool is only intended for running short tasks.
If you are intending to run a long blocking operation using Task then be sure to use TaskCreationOptions.LongRunning when creating your Task instance (this will create a new underlying Thread rather than using the ThreadPool).
Some further evidence of the ThreadPool being the issue, the following also alleviates your issue (do NOT use this):
ThreadPool.SetMinThreads(500, 500);
This demonstrates that the "slow" spawning of new ThreadPool threads was causing your bottleneck.
Tasks are executed on threads from the threadpool. The threadpool as a limited number of threads which are reused. All task, or all requested actions, are queued and executed by those threads when they are idle.
Let's assume your threadpool has 10 threads, and you have 100 tasks waiting, then 10 tasks are executed while the other 90 tasks are simply waiting in the queue untill the first 10 tasks are finished.
In the second testmethod you create 100 threads who are dedicated to their tasks. So instead of 10 threads running simultaniously, 100 threads are doing the work.
Having created the following console application I am a little puzzled why it seems to run synchronously instead of asynchronously:
class Program
{
static void Main(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
var total = CreateMultipleTasks();
stopwatch.Stop();
Console.WriteLine("Total jobs done: {0} ms", total.Result);
Console.WriteLine("Jobs done in: {0} ms", stopwatch.ElapsedMilliseconds);
}
static async Task<int> CreateMultipleTasks()
{
var task1 = WaitForMeAsync(5000);
var task2 = WaitForMeAsync(3000);
var task3 = WaitForMeAsync(4000);
var val1 = await task1;
var val2 = await task2;
var val3 = await task3;
return val1 + val2 + val3;
}
static Task<int> WaitForMeAsync(int ms)
{
Thread.Sleep(ms);
return Task.FromResult(ms);
}
}
When running the application, output is:
Total jobs done: 12000 ms
Jobs done in: 12003 ms
I would have expected somehing like:
Total jobs done: 12000 ms
Jobs done in: 5003 ms
Is this because when I use the Thread.Sleep method it stops further execution of the whole application? Or am I missing something important here?
Even when you convert to using Task.Run or Task.Delay as other answers suggest, you should avoid using the blocking Task.WaitAll anywhere inside async methods, as much as you can. Mixing asynchronous and synchronous code is usually a bad idea, it increases the number of redundantly blocked threads and promotes deadlocks.
Instead, use await Task.WhenAll and move the blocking wait to the top level (i.e., Main method in this case):
class Program
{
static void Main(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
var total = CreateMultipleTasks();
total.Wait();
stopwatch.Stop();
Console.WriteLine("Total jobs done: {0} ms", total.Result);
Console.WriteLine("Jobs done in: {0} ms", stopwatch.ElapsedMilliseconds);
}
static async Task<int> CreateMultipleTasks()
{
var task1 = Task.Run(() => WaitForMeAsync(5000));
var task2 = Task.Run(() => WaitForMeAsync(3000));
var task3 = Task.Run(() => WaitForMeAsync(4000));
await Task.WhenAll(new Task[] { task1, task2, task3 });
return task1.Result + task2.Result + task3.Result;
}
static int WaitForMeAsync(int ms)
{
// assume Thread.Sleep is a placeholder for a CPU-bound work item
Thread.Sleep(ms);
return ms;
}
}
On a side note, check Stephen Toub's "Should I expose asynchronous wrappers for synchronous methods?" and "Should I expose asynchronous wrappers for synchronous methods?"
You run the task in a synchounus manner. You can do something like this:
static async Task<int> CreateMultipleTasks()
{
var task1 = Task.Run<int>(() => WaitForMeAsync(5000));
var task2 = Task.Run<int>(() => WaitForMeAsync(3000));
var task3 = Task.Run<int>(() => WaitForMeAsync(4000));
Task.WaitAll(new Task[] { task1, task2, task3 });
return task1.Result + task2.Result + taks3.Result;
}
Using the three await in a row will NOT run the tasks in parallel. It will just free the thread while it is waiting (if you use await Task.Delay(ms) as Thread.Sleep(ms) is a blocking operation), but the current execution will NOT continue with task2 while task1 is "sleeping".
Your WaitForMeAsync method is just a simple sync method pretending to be an async one.
You don't perform anything async and Sleep() just blocks the thread.
Why would you want to delay async? (yes you can use await Task.Delay(ms)), need more input to help there.
This is probably a pretty basic question, but just something that I wanted to make sure I had right in my head.
Today I was digging with TPL library and found that there are two way of creating instance of Task class.
Way I
Task<int> t1 = Task.Factory.StartNew(() =>
{
//Some code
return 100;
});
Way II
TaskCompletionSource<int> task = new TaskCompletionSource<int>();
Task t2 = task.Task;
task.SetResult(100);
Now,I just wanted to know that
Is there any difference between these instances?
If yes then what?
The second example does not create a "real" task, i.e. there is no delegate that does anything.
You use it mostly to present a Task interface to the caller. Look at the example on
msdn
TaskCompletionSource<int> tcs1 = new TaskCompletionSource<int>();
Task<int> t1 = tcs1.Task;
// Start a background task that will complete tcs1.Task
Task.Factory.StartNew(() =>
{
Thread.Sleep(1000);
tcs1.SetResult(15);
});
// The attempt to get the result of t1 blocks the current thread until the completion source gets signaled.
// It should be a wait of ~1000 ms.
Stopwatch sw = Stopwatch.StartNew();
int result = t1.Result;
sw.Stop();
Console.WriteLine("(ElapsedTime={0}): t1.Result={1} (expected 15) ", sw.ElapsedMilliseconds, result);
As you are not firing any async operation in Way 1 above, you are wasting time by consuming another thread from the threadpool (possibly, if you don't change the default TaskScheduler).
However, in the Way 2, you are generating a completed task and you do it in the same thread that you are one. TCS can been also seen as a threadless task (probably the wrong description but used by several devs).