【发布时间】:2018-06-13 11:04:57
【问题描述】:
我正在使用新的 Span<T> 类型重写我的一些扩展方法,但我无法找到正确固定通用实例以便能够使用并行代码处理它的方法。
例如,考虑这个扩展方法:
public static unsafe void Fill<T>(this Span<T> span, [NotNull] Func<T> provider) where T : struct
{
int
cores = Environment.ProcessorCount,
batch = span.Length / cores,
mod = span.Length % cores,
sizeT = Unsafe.SizeOf<T>();
//fixed (void* p0 = &span.DangerousGetPinnableReference()) // This doesn't work, can't pin a T object
void* p0 = Unsafe.AsPointer(ref span.DangerousGetPinnableReference());
{
byte* p = (byte*)p0; // Local copy for the closure
Parallel.For(0, cores, i =>
{
byte* start = p + i * batch * sizeT;
for (int j = 0; j < batch; j++)
Unsafe.Write(start + sizeT * j, provider());
});
// Remaining values
if (mod == 0) return;
for (int i = span.Length - mod; i < span.Length; i++)
span[i] = provider();
}
}
在这里,我只想使用一些值提供程序填充输入 Span<T>,并且由于这些向量可能非常大,我想并行填充它们。
这只是一个例子,所以即使在这里使用并行代码也不是 100%必要,问题仍然存在,因为我需要使用并行 反正迟早要重新编码。
现在,这段代码确实可以工作,但是因为我从来没有真正固定输入范围,并且考虑到它很可能指向一些托管的 T[] 向量,这可以是GC 一直在移动,我想我可能很幸运地看到它在我的测试中运行良好。
所以,我的问题是:
有没有办法固定一个通用的
Span<T>实例并获得一个简单的void*指针,以便我可以在闭包中传递它以并行代码处理Span<T>实例?
谢谢!
【问题讨论】:
-
了解
Span<T>何时无法继续工作而您必须切换到Memory<T>非常重要。顺便说一句,非常丑陋的抽象泄漏,这并没有使 C# 变得更好。有一个关于它的视频:channel9.msdn.com/Events/Connect/2017/T125 -
@HansPassant 我知道我不能在闭包中使用
Span<T>,这对我来说很好,因为无论如何我已经打算使用指针来提高它们的性能,我只是在寻找一种方法固定一个ref T值(或Span<T>),这样就可以安全地使用指向它的指针,而不必担心GC 会移动东西。有什么方法可以实现(可能通过GCHandle或其他技巧)?我的意思是,出于同样的性能原因,我仍然更愿意从Span<T>获取指针并在跨度中的实际设置器上使用它,即使没有关闭问题。 -
@HansPassant 我已经打开了另一个有关使用 IL 方法固定
ref T变量的相关问题,这是链接:stackoverflow.com/questions/48095145/… 你介意看一下吗?谢谢!