这是正确的实施吗?

Sai*_*ash 8 c# long-running-processes task-parallel-library

我有一个需要从数据库中选择作业并需要处理它的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();
Run Code Online (Sandbox Code Playgroud)

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

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

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

Yuv*_*kov 4

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

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

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

经过漫长的介绍,接下来是好东西。我们真正想要做的是限制运行的线程数量并尽可能地重用它们。

对于这种工作,我会选择基于模式的TPL 数据流Producer-Consumer。举一个小例子来说明可以做什么:

// 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());
Run Code Online (Sandbox Code Playgroud)

您可以传递每个Blocka ExecutionDataflowBlockOptions,这可能会限制Bounded Capacity(BufferBlock 内的对象数量),并MaxDegreeOfParallelism告诉块您可能想要的最大并发数。

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