是什么决定TaskFactory产生的作业的线程数? [英] What determines the number of threads for a TaskFactory spawned jobs?

查看:225
本文介绍了是什么决定TaskFactory产生的作业的线程数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

var factory = new TaskFactory();
for (int i = 0; i < 100; i++)
{
    var i1 = i;
    factory.StartNew(() => foo(i1));
}

static void foo(int i)
{
    Thread.Sleep(1000);
    Console.WriteLine($"foo{i} - on thread {Thread.CurrentThread.ManagedThreadId}");
}            

我可以看到它一次只能执行4个线程(基于观察).我的问题:

I can see it only does 4 threads at a time (based on observation). My questions:

  1. 什么因素决定一次使用的线程数?
  2. 如何获取此号码?
  3. 如何更改此号码?

P.S.我的盒子有4个核心.

P.S. My box has 4 cores.

P.P.S.我需要有特定数量的任务(并且不再需要其他任务),这些任务由TPL并发处理,并最终得到以下代码:

P.P.S. I needed to have a specific number of tasks (and no more) that are concurrently processed by the TPL and ended up with the following code:

private static int count = 0;   // keep track of how many concurrent tasks are running

private static void SemaphoreImplementation()
{
    var s = new Semaphore(20, 20);  // allow 20 tasks at a time

    for (int i = 0; i < 1000; i++)
    {
        var i1 = i;

        Task.Factory.StartNew(() =>
        {
            try
            {                        
                s.WaitOne();
                Interlocked.Increment(ref count);

                foo(i1);
            }
            finally
            {
                s.Release();
                Interlocked.Decrement(ref count);
            }
        }, TaskCreationOptions.LongRunning);
    }
}

static void foo(int i)
{
    Thread.Sleep(100);
    Console.WriteLine($"foo{i:00} - on thread " + 
            $"{Thread.CurrentThread.ManagedThreadId:00}. Executing concurently: {count}");
}

推荐答案

在.NET中使用Task时,您要告诉TPL安排要执行的工作(通过TaskScheduler) ThreadPool.请注意,将尽早安排工作,但是计划程序认为合适.这意味着TaskScheduler将决定使用多少个线程来运行n个任务,以及哪个任务在哪个线程上执行.

When you are using a Task in .NET, you are telling the TPL to schedule a piece of work (via TaskScheduler) to be executed on the ThreadPool. Note that the work will be scheduled at its earliest opportunity and however the scheduler sees fit. This means that the TaskScheduler will decide how many threads will be used to run n number of tasks and which task is executed on which thread.

TPL进行了很好的调整,并在执行任务时继续调整其算法.因此,在大多数情况下,它会尽量减少争用.这意味着如果您正在运行100个任务并且只有4个内核(可以使用Environment.ProcessorCount获得),那么在任何给定时间执行4个以上的线程都是没有意义的,否则它将需要做更多的工作.上下文切换.现在有些时候您想显式地覆盖此行为.假设您需要等待某种形式的IO完成,这完全是另一回事.

The TPL is very well tuned and continues to adjust its algorithm as it executes your tasks. So, in most cases, it tries to minimize contention. What this means is if you are running 100 tasks and only have 4 cores (which you can get using Environment.ProcessorCount), it would not make sense to execute more than 4 threads at any given time, as otherwise it would need to do more context switching. Now there are times where you want to explicitly override this behaviour. Let's say in the case where you need to wait for some sort of IO to finish, which is a whole different story.

总而言之,请信任TPL.但是,如果您坚持要为每个任务生成一个线程(并非总是一个好主意!),则可以使用:

In summary, trust the TPL. But if you are adamant to spawn a thread per task (not always a good idea!), you can use:

Task.Factory.StartNew(
    () => /* your piece of work */, 
    TaskCreationOptions.LongRunning);

这告诉 Default Taskscheduler明确为该工作生成新线程.

This tells the DefaultTaskscheduler to explicitly spawn a new thread for that piece of work.

您也可以使用自己的Scheduler并将其传递给TaskFactory.您可以找到一大堆Schedulers HERE .

You can also use your own Scheduler and pass it in to the TaskFactory. You can find a whole bunch of Schedulers HERE.

请注意,另一种选择是使用 PLINQ ,默认情况下,它再次分析您的查询并决定并行化查询是否会产生任何好处,在遇到阻塞IO的情况下某些启动多个线程将导致更好的执行,您可以通过使用 WithExecutionMode(ParallelExecutionMode.ForceParallelism) 强制并行化,然后可以使用 WithDegreeOfParallelism 来提示要使用多少个线程但是请记住,没有<​​b>不能保证,您会得到很多线程,例如

Note another alternative would be to use PLINQ which again by default analyses your query and decides whether parallelizing it would yield any benefit or not, again in the case of a blocking IO where you are certain starting multiple threads will result in a better execution you can force the parallelism by using WithExecutionMode(ParallelExecutionMode.ForceParallelism) you then can use WithDegreeOfParallelism, to give hints on how many threads to use but remember there is no guarantee you would get that many threads, as MSDN says:

设置查询中要使用的并行度.程度 并行度是同时执行的任务的最大数量 将用于处理查询.

Sets the degree of parallelism to use in a query. Degree of parallelism is the maximum number of concurrently executing tasks that will be used to process the query.

最后,我高度建议阅读 关于ThreadingTPL的大量文章.

Finally, I highly recommend having a read of THIS great series of articles on Threading and TPL.

这篇关于是什么决定TaskFactory产生的作业的线程数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆