[英]Prevent Parallel operation executing in sequential batches
I have 8 logical processors.我有 8 个逻辑处理器。 When executing the following code
执行以下代码时
public void test()
{
Parallel.For(1, 1001, i => { IntensiveWork(i); });
}
private static void IntensiveWork(int i)
{
Random r = new Random();
Thread.Sleep(r.Next(i * 1));
}
I notice that the Parallel.For
makes multiple batches of 8 jobs.我注意到
Parallel.For
进行了多批 8 个作业。 Each batch will be executed sequentially.每批将按顺序执行。 The issue in this is that if 7/8 jobs in the batch finished, then the next batch will keep waiting for the last job to finish.
这里的问题是,如果批次中有 7/8 个作业完成,那么下一个批次将继续等待最后一个作业完成。 This means that 7 cores will not be busy.
这意味着7个核心不会忙。 Is there a better way to implement parallelism is C#, in which once a job in the batch finishes it will assign that core another job.
有没有更好的方法来实现并行性是 C#,其中一旦批处理中的作业完成,它将为该核心分配另一个作业。
You can make single queue that multiple tasks will read from. 您可以将多个任务从中读取单个队列。
static void test()
{
ConcurrentQueue<int> queue = new ConcurrentQueue<int>(Enumerable.Range(1, 1000));
int taskCount = Environment.ProcessorCount;
Task[] tasks = new Task[taskCount];
for (int taskIndex = 0; taskIndex < taskCount; taskIndex++)
{
Task task = Task.Factory.StartNew(() => IntensiveWorkTask(queue));
tasks[taskIndex] = task;
}
Task.WaitAll(tasks);
}
private static void IntensiveWorkTask(ConcurrentQueue<int> queue)
{
while (queue.TryDequeue(out int value))
IntensiveWork(value);
}
private static void IntensiveWork(int i)
{
Random r = new Random();
Thread.Sleep(r.Next(i * 1));
}
Try Microsoft's Reactive Framework (aka Rx) - just NuGet System.Reactive
and then add using System.Reactive.Linq;
尝试使用Microsoft的Reactive Framework(aka Rx)-仅NuGet
System.Reactive
,然后using System.Reactive.Linq;
添加using System.Reactive.Linq;
- then you can do this: -那么您可以执行以下操作:
public void test()
{
IObservable<Unit> query =
Observable
.Range(1, 1000)
.SelectMany(i =>
Observable
.Start(() => IntensiveWork(i)));
IDisposable subscription = query.Subscribe();
}
private static Random r = new Random();
private static void IntensiveWork(int i)
{
Thread.Sleep(r.Next(i * 1));
}
Play with the .Subscribe(...
to be able to respond to each work item when it is completed. 播放
.Subscribe(...
,以便能够在完成每个工作项目时对其进行响应。
Instead of:代替:
Parallel.For(1, 1001, parallelOptions, i => IntensiveWork(i));
You should do:你应该做:
IEnumerable<int> source = Enumerable.Range(1, 1000);
Partitioner<int> partitioner = Partitioner
.Create(source, EnumerablePartitionerOptions.NoBuffering);
Parallel.ForEach(partitioner, parallelOptions, i => IntensiveWork(i));
The partitioning strategy of the Parallel.For
is a combination of range partitioning and chunk partitioning, which is not appropriate for your case, and cannot be configured. Parallel.For
的分区策略是范围分区和块分区的组合,不适合您的情况,无法配置。 What you want is a partitioner with load balancing behavior, with chunk partitioning disabled.你想要的是一个具有负载平衡行为的分区器,禁用块分区。 That's why you have to switch to
Parallel.ForEach
, and configure the partitioner with the EnumerablePartitionerOptions.NoBuffering
option.这就是为什么您必须切换到
Parallel.ForEach
并使用EnumerablePartitionerOptions.NoBuffering
选项配置分区程序的原因。
The parallelOptions
is shown below. parallelOptions
如下所示。 It's always a good idea to specify explicitly the MaxDegreeOfParallelism
, for example to Environment.ProcessorCount
, instead of relying on the default -1
(unlimited) configuration that saturates the ThreadPool
.明确指定
MaxDegreeOfParallelism
始终是一个好主意,例如Environment.ProcessorCount
,而不是依赖使ThreadPool
饱和的默认-1
(无限制)配置。
ParallelOptions parallelOptions = new()
{
MaxDegreeOfParallelism = Environment.ProcessorCount
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.