这是正确的实现吗?

本文关键字:实现 | 更新日期: 2023-09-27 18:09:58

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

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

我是任务并行库的新手。我以以下方式实现了示例逻辑:

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

但是,这会创建很多线程。因为循环重复了100次,所以它创建了100个线程。

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

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

这是正确的实现吗?

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

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

除此之外,可能运行的并发Threads的数量取决于您的机器正在封装的内核数量,并且创建的线程数量大于您的机器拥有的内核数量将开始导致Context Switching,这从长远来看可能会减慢您的工作速度。

在长时间的介绍之后,来看看精彩的内容。我们真正想做的是限制运行的线程数量,并尽可能地重用它们。

对于这种工作,我会使用基于Producer-Consumer模式的TPL数据流。这只是一个可以做什么的小例子:

// a BufferBlock is an equivalent of a ConcurrentQueue to buffer your objects
var bufferBlock = new BufferBlock<object>();
// An ActionBlock to process each object and do something with it
var actionBlock = new ActionBlock<object>(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.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…)调用。实际的顺序取决于执行。