我有一个Windows服务,需要从数据库中选择作业并需要对其进行处理。

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

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

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时要记住的一个重要因素是,操作系统必须分配多个逻辑实体才能运行该当前线程:

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

  • 除此之外,可能运行的并发Threads的数量取决于计算机要打包的内核数,并且创建大于计算机所拥有的内核数的线程数量将开始导致Context Switching,从长远来看,这会导致Producer-Consumer。可能会减慢您的工作速度。

    因此,经过漫长的介绍之后,您将了解到好东西。我们实际上想要做的是限制正在运行的线程数,并尽可能地重用它们。

    对于这种工作,我将使用基于Block模式的TPL Dataflow。只是可以做的一个小例子:
    // 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());
    

    您可以为每个ExecutionDataflowBlockOptions传递一个Bounded Capacity,它可以限制MaxDegreeOfParallelism(BufferBlock中对象的数量),而ojit_code则告诉该块您可能需要的最大并发数量。

    有一个很好的示例here可以帮助您入门。

    关于c# - 这是正确的执行方式吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24380518/

    10-16 09:06