【发布时间】:2019-01-02 08:08:15
【问题描述】:
场景是这样的:在 Parallel.For 内部,一个数组用于非并行 for。数组的所有元素都被覆盖,因此在技术上没有必要分配和初始化它(这总是在构造时发生,据我从 C# 教程中推断):
float[] result = new float[16384];
System.Threading.Tasks.Parallel.For(0,16384,x =>
{
int[] histogram = new int[32768]; // allocation and initialization with all 0's, no?
for (int i = 0; i < histogram.Length; i++)
{
histogram[i] = some_func(); // each element in histogram[] is written anew
}
result[x] = do_something_with(histogram);
});
顺序代码中的解决方案很简单:将数组拉到外部for循环的前面:
float[] result = new float[16384];
int[] histogram = new int[32768]; // allocation and initialization with
for(x = 0; x < 16384; x++)
{
for (int i = 0; i < histogram.Length; i++)
{
histogram[i] = some_func();
}
restult[x] = do_something_with(histogram);
}
现在在外循环中既没有分配也没有徒劳的 0-ing。
在并行版本中,这肯定是一个糟糕的举动,或者并行进程正在破坏彼此的直方图结果,或者 C# 足够聪明地锁定 histogram 从而关闭任何并行性。分配histogram[16384,32768] 同样是浪费。我现在正在尝试的是
public static ParallelLoopResult For<TLocal>(
int fromInclusive,
int toExclusive,
Func<TLocal> localInit,
Func<int, ParallelLoopState, TLocal, TLocal> body,
Action<TLocal> localFinally
)
库构造(函数?),但由于这是我第一次尝试在 C# 中进行并行编程,我充满了疑问。以下是顺序情况的正确翻译吗?
float[] result = new float[16384];
System.Threading.Tasks.Parallel.For<short[]>(0, 16384,
() => new short[32768],
(x, loopState, histogram) =>
{
for (int i = 0; i < histogram.Length; i++)
{
histogram[i] = some_func();
}
result[x] = do_something_with(histogram);
return histogram;
}, (histogram) => { });
【问题讨论】:
-
您考虑过将结果写入 ConcurrentBag 吗?这是我认为您正在寻求的线程安全实现:msdn.microsoft.com/en-us/library/dd381779(v=vs.110).aspx
-
@mjwills 澄清一下:如果此代码在 32768 核机器上运行,则需要这么多版本的直方图,但较小规模的并行性表明我不会分配全部如果在任何时候我只需要一把可以立即处理的。
-
一种选择是为
Parallel.For设置MaxDegreeOfParallelism。然后保持与 MaxDop 大小相同的数组池(基本上是数组数组)。Interlocked.Increment获取每次迭代的唯一 ID。iterationID % MaxDop获取要使用的池的索引。这为您提供了一个小数组(例如 8 个数组)而不是需要 16384 个数组,并保证一次只有一个线程使用它。 公平地说,这与您在Parallel.For线程本地解决方案中使用的方法基本相同。 -
你能详细说明你想用这段代码完成什么,可能有更好的方法。
-
具体你关心用多少线程来处理结果?
标签: c# for-loop task-parallel-library allocation