我正在使用 Parallel.Foreach
对大型数组进行操作,其中每个数组元素对应于位图中的一行。但是,Parallel.Foreach
似乎分配固定数量的线程,比如 6 个线程,并将数组的 1/6 分配给第一个线程,将数组的 1/6 分配给下一个线程命令。示例:
[0]=>thread1, [1]=>thread1, [2]=>thread1, [3]=>thread1
[4]=>thread2, [5]=>thread2, [6]=>thread2, [7]=>thread2,
.. and so forth
粗略地说,我想要的是一个交错模式,它在数组索引的每个增量的线程之间交替......例如:
[0]=>thread1 [1]=>thread2 [2]=>thread3 [4]=>thread4, [5]=>thread1, [6]=>thread2, etc...
有没有办法改变 Parallel.Foreach 分配给每个主动执行的并行线程的交错模式?
我正在尝试使用 gif 交错模式渲染图像,而不是让位图线在图像上以 6 条不同的线顺序呈现,向下填充...
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Concurrent;
//…
void button_click() {
Task.Run(() =>{
start_task();
});
}
int ds_height=600;
public bool start_task()
{
var cpu75 = Convert.ToInt32(Math.Ceiling((
Environment.ProcessorCount * 0.75) * 1.0));
//MandelInit();
int[] ytmp;
int version = 2;
if (version == 1) {
ytmp = MandelYLace();
}
else {
int[] ytmp = new int[ds_height];
for(int i=0; i < ds_height; i++)
{
ytmp[i] = i;
}
Parallel.ForEach(
ytmp, //ylace,
new ParallelOptions { MaxDegreeOfParallelism = cpu75 },
yy => {
//ybuff[yy] = MandelLine(yy);
//ydone.Enqueue(yy);
}
);
stop = true;
return true;
}
// Interlace Y-Lines using GIF Interlaced method
int[] MandelYLace()
{
var ylace = new int[ds_height];
for (int y = 0, yg=0, yy=0; y < ds_height; y++)
{
ylace[y] = yy;
if (yg == 0 || yg == 1)
yy += 8;
else if (yg == 2)
yy += 4;
else if (yg == 3)
yy += 2;
if (yy >= ds_height)
{
yg = (yg + 1) % 4;
if (yg == 1) yy = 4;
else if (yg == 2) yy = 2;
else if (yg == 3) yy = 1;
else if (yg == 0) yy = 0;
}
}
return ylace;
}
最佳答案
在这里您可以看到隔行扫描第一遍的快照......一些任务滞后......因此缺少行......它们最终出现:
int ds_height=600;
public bool start_task()
{
var cpu75 = Convert.ToInt32(Math.Ceiling((
Environment.ProcessorCount * 0.75) * 1.0));
var partitioner = new InterlacePartitioner(ds_height);
Parallel.ForEach(
partitioner,
new ParallelOptions { MaxDegreeOfParallelism = cpu75 },
yy => {
//ybuff[yy] = MandelLine(yy);
//ydone.Enqueue(yy);
}
);
stop = true;
return true;
}
使用共享 IEnumerator 实现 gif 样式行交错的自定义 PLINQ 分区器:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Collections;
namespace NetMandelbrot
{
// This is both the Interlaced Line IEnumerator and IEnumerable
public class ImageInterlace :
IEnumerable<int>, IEnumerable, IEnumerator<int>, IDisposable
{
int[] Lines;
int Pos;
public ImageInterlace(int ImageHeight)
{
Pos = -1;
Lines = GetLines(ImageHeight);
}
// Interlace Y-Lines using GIF Interlaced method
int[] GetLines(int ImageHeight)
{
var ylace = new int[ImageHeight];
for (int y = 0, yg = 0, yy = 0; y < ImageHeight; y++)
{
ylace[y] = yy;
if (yg == 0 || yg == 1)
yy += 8;
else if (yg == 2)
yy += 4;
else if (yg == 3)
yy += 2;
if (yy >= ImageHeight)
{
yg = (yg + 1) % 4;
if (yg == 1) yy = 4;
else if (yg == 2) yy = 2;
else if (yg == 3) yy = 1;
else if (yg == 0) yy = 0;
}
}
return ylace;
}
#region Implementation of IDisposable
public void Dispose()
{
}
#endregion
#region Implementation of IEnumerable<int>
public IEnumerator<int> GetEnumerator()
{
return this;
}
#endregion
// Legacy C#
#region Implementation of IEnumerable
IEnumerator IEnumerable.GetEnumerator()
{
return this;
}
#endregion
#region Implementation of IEnumerator<int>
public bool MoveNext()
{
bool done;
lock (Lines)
{
if (Pos < Lines.Length)
{
Pos++;
}
done = (Pos < Lines.Length);
}
return done;
}
public void Reset()
{
lock (Lines)
{
Pos = -1;
}
}
public int Current
{
get
{
int nextline;
lock (Lines)
{
if (Pos >= Lines.Length)
{
nextline = -1;
}
else
{
nextline = Lines[Pos];
}
}
return nextline;
}
}
// C# Legeacy
object IEnumerator.Current
{
get { return Current; }
}
#endregion
}
public class InterlacePartitioner : Partitioner<int>
{
int ImageHeight = 0;
ImageInterlace imageinterlace;
public InterlacePartitioner(int imageHeight)
{
ImageHeight = imageHeight;
imageinterlace = new ImageInterlace(ImageHeight);
}
public override IList<IEnumerator<int>> GetPartitions(int partitionCount)
{
int i = 0;
List<List<int>> partz = new List<List<int>>();
foreach (var yline in imageinterlace)
{
partz[i % partitionCount].Add(yline);
i++;
}
return (IList<IEnumerator<int>>)partz;
}
public override IEnumerable<int> GetDynamicPartitions()
{
return imageinterlace;
}
// Not consumable from Parallel.ForEach.
public override bool SupportsDynamicPartitions
{
get
{
return true;
}
}
} //end of class
}
关于c# - 有没有办法改变 Parallel.Foreach 交织其操作的数组的方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52457816/