简体   繁体   English

任务调度程序中的手动线程与Parallel.Foreach

[英]Manual threads vs Parallel.Foreach in task scheduler

I have a Windows Service that processes tasks created by users. 我有一个Windows服务,可以处理用户创建的任务。 This Service runs on a server with 4 cores. 此服务在具有4个核心的服务器上运行。 The tasks mostly involve heavy database work (generating a report for example). 这些任务主要涉及繁重的数据库工作(例如,生成报告)。 The server also has a few other services running so I don't want to spin up too many threads (let's say a maximum of 4). 该服务器还运行着其他一些服务,因此我不想增加太多线程(比如说最多4个)。

If I use a BlockingCollection<MyCustomTask> , is it a better idea to create 4 Thread objects and use these to consume from the BlockingCollection<MyCustomTask> or should I use Parallel.Foreach to accomplish this? 如果我使用BlockingCollection<MyCustomTask> ,那么最好是创建4个线程对象并使用它们从BlockingCollection<MyCustomTask>使用,还是应该使用Parallel.Foreach来实现这一点?

I'm looking at the ParallelExtensionsExtras which contains a StaTaskScheduler which uses the former, like so (slightly modified the code for clarity): 我正在查看ParallelExtensionsExtras ,其中包含一个使用前者的StaTaskScheduler,就像这样(为清晰起见,对代码进行了少许修改):

var threads = Enumerable.Range(0, numberOfThreads).Select(i =>
                       {
                           var thread = new Thread(() =>
                           {
                               // Continually get the next task and try to execute it.
                               // This will continue until the scheduler is disposed and no more tasks remain.
                               foreach (var t in _tasks.GetConsumingEnumerable())
                               {
                                   TryExecuteTask(t);
                               }
                           });
                           thread.IsBackground = true;
                           thread.SetApartmentState(ApartmentState.STA);
                           return thread;
                       }).ToList();

            // Start all of the threads
            threads.ForEach(t => t.Start());

However, there's also a BlockingCollectionPartitioner in the same ParallelExtensionsExtras which would enable the use of Parallel.Foreach on a BlockingCollection<Task> , like so: 但是,在相同的ParallelExtensionsExtras中也有一个BlockingCollectionPartitioner ,可以在BlockingCollection<Task>上使用Parallel.Foreach ,如下所示:

 var blockingCollection = new BlockingCollection<MyCustomTask>();
        Parallel.ForEach(blockingCollection.GetConsumingEnumerable(), task =>
        {
            task.DoSomething();
        });

It's my understanding that the latter leverages the ThreadPool . 据我了解,后者利用ThreadPool Would using Parallel.ForEach have any benefits in this case? 在这种情况下,使用Parallel.ForEach有什么好处吗?

This answer is relevant if Task class in your code has nothing to do with System.Threading.Tasks.Task. 如果您代码中的Task类与System.Threading.Tasks.Task无关,则此答案很重要。

As a simple rule, use Parallel.ForEach to run tasks that will end eventually. 作为简单的规则,请使用Parallel.ForEach运行最终将结束的任务。 Like execute some work in parallel with some other work 就像同时执行某些工作一样

Use Threads when they run routine for the whole life of application. 当线程在整个应用程序的整个生命周期中运行例程时,请使用它们。

So, it looks like in your case you should use Threads approach. 因此,在您的情况下,您应该使用线程方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM