views:

49

answers:

2

Hi

I'm working with .NET new TPL library and faced with some strange behavior for me I cannot explain. For some reason nested task is not started in my case. I've simplified the solution I have to the following:

        bool flag = false;

        for (int i = 0; i < 5; i++)
        {
            Task.Factory.StartNew(() =>
                         {
                            while (true) // a lot of newcoming tasks
                            {
                                Thread.Sleep(200); //do some work
                                Task.Factory.StartNew(() =>
                                             {
                                                 flag = true;
                                              });
                            }
                         });
        }

        Thread.Sleep(2000);
        Assert.IsTrue(flag);

I have 5 Tasks that running concurrently. Each tasks retrieve some elements from pending queue, performs some operation and then try to run nested task for the results of this operation. The problem is that if there are too many elements (while(true) simulates this) and all 5 tasks are constantly running nested tasks are not started. The can only be started after most of tasks with while loop finish their execution.

It seems something wrong with while statements that blocks nested tasks to run, but I don't know what :)

A: 

I think you'll find that the library only starts parallel tasks roughly based on the number of cores you have available. i.e. it's not a good choice for tasks which are I/O bound where you might actually want to use significantly more threads than you have CPUs.

You're not really saying that the nested tasks don't start, are you? You're just saying that they don't get started at the point you'd like them to, but start later.

Will Dean
Yes. They start later, but I want them starting parallel to executing tasks. If I change limit for 'i' index in the loop to, for example, 10 I will have 10 threads created and running. But no one nested task will be running parallel to these tasks.
lostaman
Adding TaskCreationOptions.LongRunning for parent tasks solved the problem.
lostaman
It solve problem in the example below but not in my project :(
lostaman
+1  A: 

Task.Factory.StartNew doesn't start a task, it adds the task to the list of tasks to be scheduled and the scheduler gets to decide when to run the task based on things like; number of available cores (size of thread pool), current CPU load and the throughput of existing work.

You should read the section about task scheduling here:

http://parallelpatterns.codeplex.com/releases/view/48562

Page 63 of the PDF onwards.

The LongRunning option "fixes" your problem by bypassing the thread pool entirely. This has some disadvantages in that it will allow you to create more threads than your system should really be using, this will degrade the performance by causing excessive context switching.

Experiments like the code you have above using thread sleep are misleading because they "fool" the scheduler. It sees that it added more work and yet the CPU load hasn't increased.63 You should replace the sleep with a tight loop which contains math (like calculating Sqrt() for example.

Why not simply have a single outer loop which reads items from a queue and executes them on Task. That way your application will make the most use of available parallelism of the system without overloading it.

The following answer might be worth a look:

http://stackoverflow.com/questions/3003656/parallel-task-library-waitany-design/3122818#3122818

Ade Miller