这是正确的实施吗?

我有一个Windows服务需要从数据库中选择作业并需要处理它。

在这里,每项工作都是一个扫描过程,大约需要10分钟才能完成。

我是Task Parallel Library的新手。 我已通过以下方式实现为示例逻辑:

Queue queue = new Queue(); for (int i = 0; i < 10000; i++) { queue.Enqueue(i); } for (int i = 0; i  { var Objdata = (Queue)data; Console.WriteLine(Objdata.Dequeue()); Console.WriteLine( "The current thread is " + Thread.CurrentThread.ManagedThreadId); }, queue, TaskCreationOptions.LongRunning); } Console.ReadLine(); 

但是,这创造了很multithreading。 由于循环重复100次,因此创建了100个线程。

创建那么多并行线程是正确的方法吗?

有没有办法将线程数限制为10(并发级别)?

分配新Threads时要记住的一个重要因素是操作系统必须分配许多逻辑实体才能运行当前线程:

  1. 线程内核对象 – 用于描述线程的对象,包括线程的上下文,cpu寄存器等
  2. 线程环境块 – 用于exception处理和线程本地存储
  3. 用户模式堆栈 – 1MB堆栈
  4. 内核模式堆栈 – 用于将参数从用户模式传递到内核模式

除此之外,可能运行的并发Threads数取决于您的机器正在打包的核心数量,并且创建大于您的机器拥有的核心数量的线程数量将开始导致Context Switching运行可能会减慢你的工作。

经过长时间的介绍,到了好东西。 我们实际想要做的是限制运行的线程数,并尽可能地重用它们。

对于这种工作,我会选择基于Producer-Consumer模式的TPL Dataflow 。 只是一个可以做的事情的小例子:

 // a BufferBlock is an equivalent of a ConcurrentQueue to buffer your objects var bufferBlock = new BufferBlock(); // An ActionBlock to process each object and do something with it var actionBlock = new ActionBlock(obj => { // Do stuff with the objects from the bufferblock }); bufferBlock.LinkTo(actionBlock); bufferBlock.Completion.ContinueWith(t => actionBlock.Complete()); 

您可以向每个Block传递一个ExecutionDataflowBlockOptions ,它可以限制Bounded Capacity (BufferBlock中的对象数)和MaxDegreeOfParallelism ,它告诉块您可能需要的最大并发数。

这里有一个很好的例子可以帮助您入门。

很高兴你问,因为你的意思是对的 – 这不是最好的方法。

Task的概念不应与Thread混淆。 Thread可以与厨房中的厨师进行比较,而Task是客户订购的菜肴。 你有一堆厨师,他们按照一些顺序处理菜单(通常是FIFO)。 厨师完成一道菜然后继续前进。 线程池的概念是相同的。 您创建了一堆要完成的任务,但您不需要为每个任务分配新线程。

好吧,实际比特来做。 有几个。 第一个是ThreadPoll.QueueUserWorkItem 。 ( http://msdn.microsoft.com/en-us/library/system.threading.threadpool.queueuserworkitem(v=vs.110).aspx )。 使用Parallel库也可以使用Parallel.For ,它将根据系统中可用的实际CPU核心数自动生成线程。

 Parallel.For(0, 100, i=>{ //here, this method will be called 100 times, and i will be 0 to 100 WaitForGrassToGrow(); Console.WriteLine(string.Format("The {0}-th task has completed!",i)); }); 

请注意,无法保证Parallel.For调用的方法按顺序调用(0,1,2,3,4,5 …)。 实际顺序取决于执行。