Decentralized Task Scheduling Techniques in .NET

889 views Asked by At

I have been trying to learn more details on CLR 4.0. and the ThreadPool and the different strategies that Microsoft recommended. I consider myself fairly up-to-date on a lot of these topics, and use threading and concurrent code on a daily basis.

I have been goign back through the Parallel Patterns and Practices again recently, and am a bit caught on the Decentralized Scheduling Techniques section which gives a brief overview of 'Work Stealing' and local vs global thread queues.

The questions I have are:

1) Is work stealing opt-in or opt-out? Same for using local thread queues? Or does this happen by default with CLR 4.0?

2) Do we have control over whether we are using local or global thread queues? If so, through what API calls?

2

There are 2 answers

1
Servy On

You have no control over either. That is describing how the default thread scheduler schedules it's tasks. That is simply how it works. You can create your own TaskScheduler entirely, and write your own scheduler from scratch, and you can also use TaskCreationOptions to provide some hints to the scheduler (which, if it wants, it's free to ignore) but none of those options allow you to specify which of those queues a task goes into.

The primary point of the Task model is that you don't need to worry about such details; the intent is that the work can be scheduled by any of the worker threads, in any order, and that you're allowing the framework scheduler to do it's best to optimize the work. Adding constants makes it harder for it to do that effectively. As previously mentioned, you can use a custom task scheduler if you require a radically different algorithm for scheduling tasks.

0
Thomas B. On

1) Is work stealing opt-in or opt-out? Same for using local thread queues? Or does this happen by default with CLR 4.0?

Work stealing is the default. With .NET 4.0 the ThreadPool was extended with work-stealing behaviour. And the default TaskScheduler (System.Threading.Tasks.ThreadPoolTaskScheduler) is based on the ThreadPool Class. So it is the default, since 4.0.

2) Do we have control over whether we are using local or global thread queues? If so, through what API calls?

As @Servy already mentioned, for full control you need to write your own TaskScheduler. (as described in How to: Create a Task Scheduler That Limits Concurrency)

But you can somehow influence the queuing behaviour with the TaskCreationOptions:

  • LongRunning: The Task gets a newly created Thread outside the Treadpool
  • PreferFairness: New child tasks (which normally will end up in the local queue of the thread that executed the parent task) will end up in the global queue. Thus, if all tasks are marked with "PreferFairness", work stealing and local queuing would be deactivated effectively.

But, as this article about PreferFairness underlines, the implementation detail / effect of these flags could change with new implementations of the .NET framework.