How to pin a generic Span<T> instance to work on it with Parallel.For?

梦想与她 提交于 2019-12-05 03:04:35

I think I might have found a workaround using one of the new methods in the Unsafe class, I've tested it and so far it seems to work. Here it is:

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,
        size = Unsafe.SizeOf<T>();
    ref T r0 = ref span.DangerousGetPinnableReference();
    fixed (byte* p0 = &Unsafe.As<T, byte>(ref r0))
    {
        byte* p = p0;
        Parallel.For(0, cores, i =>
        {
            byte* pi = p + i * batch * size;
            for (int j = 0; j < batch; j++, pi += size)
                Unsafe.Write(pi, provider());
        }).AssertCompleted();

        // Remaining values
        if (mod < 1) return;
        for (int i = span.Length - mod; i < span.Length; i++)
            Unsafe.Write(p + i * size, provider());
    }
}

Basically, since I can't pin a ref T value, I tried to get a ref byte variable using Unsafe.As<T, byte>(ref T value) and to pin that one instead. Since it points to the same address, I think (hope) it's pinned just fine, it should be doing the same thing in IL.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!