简体   繁体   English

如何在 C# 中高效地并行运行代码?

[英]How to efficiently run code in parallel in C#?

I thought that my problem is the following -- how to prepare for parallel execution?我认为我的问题如下——如何为并行执行做准备?

My current code resemble this pattern:我当前的代码类似于这种模式:

  var worker = new Worker();
  while (true)
    worker.RandomTest();

RandomTest is mostly CPU-bound. RandomTest主要受 CPU 限制。 On rare occasions, workers will write to a file (after obtaining a lock on it), but this is so infrequent that I/O delays shouldn't need to be considered.在极少数情况下,worker 会写入文件(在获得对文件的锁定之后),但这种情况很少见,因此不需要考虑 I/O 延迟。

I would like to run this in parallel, I could use Parallel.For and use some big number as an upper limit (instead while ), but I have problems how to prepare for such execution, because I don't want to create worker at each iteration.我想并行运行它,我可以使用Parallel.For并使用一些大数字作为上限(而不是while ),但我有问题如何准备这样的执行,因为我不想创建工人每次迭代。

To prepare I would need to know parallel pool size in advance and also inside loop the index of the thread/task/job so I would know how to associate current execution path with the worker.为了做好准备,我需要提前知道并行池的大小,并且还需要知道线程/任务/作业的索引在内部循环,这样我才能知道如何将当前执行路径与工作线程相关联。


As it turns out my problem is more fundamental.事实证明,我的问题更为根本。 I couldn't figure out how to make preparation, so since I have endless loop I though why not:我不知道如何做准备,所以既然我有无限循环,我想为什么不呢:

  Parallel.Loop(0,1000,(i,_) => {
    var worker = new Worker();
    while (true)
      worker.RandomTest();
  }

Till now I assumed the launched executions will be in sane limits in comparison to available CPU cores.到目前为止,我认为启动的执行与可用的 CPU 内核相比将处于合理的范围内。 But no -- Parallel creates new iterations like crazy, so already created jobs are basically stalled because of the incoming flood of the new ones.但是没有——Parallel 疯狂地创建新的迭代,所以已经创建的工作基本上因为新工作的涌入而停滞不前。

Of course I can hardcode the fixed number how many parallel jobs to run, but then the responsibility of figuring out how much is not too much and not too little is on me.当然,我可以对要运行的并行作业的固定数量进行硬编码,但是计算出多少不能太多也不能太少的责任在我身上。

I know how to put a fixed number, but how to put a good number?我知道怎么放固定号,但是怎么放好号呢? Ie when I run program on different machine or in different conditions (for example with CPU-demanding process in the background)?即当我在不同的机器上或在不同的条件下运行程序时(例如在后台使用 CPU 要求很高的进程)?

Here Worker is not thread safe type, thus I create as many worker as there are jobs to do.这里的Worker不是线程安全类型,因此我创建了与要执行的工作一样多的 worker。

One way to solve this problem is to start a number of threads equal to the number of cores, and do an infinite while loop in each thread:解决这个问题的一种方法是启动与内核数量相等的线程, while在每个线程中进行无限循环:

for (int i = 0; i < Environment.ProcessorCount; i++)
{
    _ = new Thread(() =>
    {
        Worker worker = new();
        while (true) worker.RandomTest();
    });
}

These threads are foreground threads, so they'll keep the program alive even after exiting the Main method.这些线程是前台线程,因此即使在退出Main方法后它们也会使程序保持活动状态。 In case any of the loops fail, the whole program will crash immediately with an unhandled exception.如果任何循环失败,整个程序将立即崩溃并出现未处理的异常。 This primitive behavior might be closer to what you want to do, than the sophisticated Parallel class with its obscure partitioners.这种原始行为可能更接近您想要做的事情,而不是复杂的Parallel类及其晦涩的分区程序。

Regarding the optimal degree of parallelism, for CPU-bound workloads it is usually Environment.ProcessorCount .关于最佳并行度,对于受 CPU 限制的工作负载,通常是Environment.ProcessorCount With this configuration the parallel execution will use all the cores of your machine, without too much thread-switching.使用此配置,并行执行将使用您机器的所有核心,而无需太多线程切换。

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

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