I have a windows C# WinForms application. I'm confused by the way the default task scheduler is behaving for parallel class in task parallel library. When I call Parallel.For
inside ParallelForEach
method I was expecting the numbers to get printed in jumbled fashion in output window through Console.WriteLine
statement inside "Method1" method.
Since I'm not passing any ParallelOptions
to configure the scheduler for Parallel class it should be using default task scheduler but numbers are getting printed in serial fashion like 0,1,2,3,.....49. This gives me an impression that all the tasks which are getting executed are running on UI synchronization context in serial fashion one by one. I also verified this by updating the text property of UI text box with value of i and it didn't throw me an InvalidOperationException
which happens in case of thread-pool thread.
But if I uncomment the first statement inside Method1
function to simulate long running task the output gets jumbled. Why is the CLR is making this decision to use the UI thread to run all those 50 tasks? Why is the CLR is making this decision on my behalf when I have not asked it to do so just on the basis of the fact that initially my task is small compute bound task? How does the CLR really evaluate the fact that a particular method will take long time to execute or small time to execute?
Hardware information: My computer is a Windows Server 2008 box with four cores.
namespace WindowsFormsApplication1
{
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Schedulers;
using System.Windows.Forms;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ParallelForEach();
}
private void ParallelForEach()
{
Console.WriteLine("With default task scheduler");
Parallel.For(0, 50, i => Method1(i));
}
private void Method1(int i)
{
//System.Threading.Thread.Sleep(2000);
//textBox1.Text = i.ToString();
Console.WriteLine(i);
//do some work
}
}
}
By default,
Parallel.For()
uses the defaultTaskScheduler
(which uses theThreadPool
) and also the current thread (it has to be blocked until all iterations are complete, so it might as well do some useful work, instead of just waiting). So, if you have a small number iterations that finish fast, it's possible that the whole loop will execute on the current loop, before all theTask
s that are scheduled to theTaskScheduler
even start. This explains the behavior you're seeing in both cases.Note that you shouldn't block the UI thread for a long period of time, doing that freezes the UI of the application. This implies that you shouldn't use
Parallel.For()
on the UI thread.