Parallel.For循环中使用Span<float>遇阻,请求技术解决方案
问题解决:Parallel.For中使用Span的替代方案
问题原因
Span
将Span构造放在Parallel.For内部时循环无法退出,大概率是迭代逻辑中出现了其他问题(比如索引计算错误导致死循环、线程阻塞等),且这种做法会重复创建Span,完全没必要。
可行实现方案
方案1:改用Memory(推荐)
Memory.Span属性仍能获得Span
// 将byte数组转换为Memory<float> Memory<float> floatMemory = MemoryMarshal.Cast<byte, float>(posColBuffer.AsMemory()); Parallel.For(0, posColBuffer.Length / 4, i => { var scalar = calcScalar(i); float color = calcColor(i); var id0 = 3 * i; // 通过.Span获取Span<float>进行元素操作 Span<float> floats = floatMemory.Span; for (int j = 0; j < 3; j++) { floats[i + j] = directions[id0 + j] * scalar; floats[colorOffset + i + j] = color; } });
方案2:使用Parallel.For的本地状态重载
如果坚持使用Span
// 先将byte数组转为Memory<byte>,方便后续跨线程安全访问 var byteMemory = posColBuffer.AsMemory(); Parallel.For( // 循环起始与结束索引 0, posColBuffer.Length / 4, // 线程本地初始化:每个线程创建一次Span<float> () => MemoryMarshal.Cast<byte, float>(byteMemory).Span, // 循环体:使用本地状态的localFloats (i, loopState, localFloats) => { var scalar = calcScalar(i); float color = calcColor(i); var id0 = 3 * i; for (int j = 0; j < 3; j++) { localFloats[i + j] = directions[id0 + j] * scalar; localFloats[colorOffset + i + j] = color; } return localFloats; }, // 线程本地清理:此处无需操作 (localFloats) => { } );
注意事项
- 确保
directions数组和colorOffset的取值是线程安全的,避免并行过程中出现竞争访问。 - 验证
posColBuffer.Length / 4的计算是否正确:byte数组转float数组时,长度必须是4的倍数,否则会抛出异常。
内容的提问来源于stack exchange,提问作者Plat00n
相关产品推荐
相关产品推荐

