Небезопасно. Начиная с массива byte до ulong array

В настоящее время я смотрю на перенос моего metro hash implementon для использования функций С# 7, так как несколько частей могут получить прибыль от локальных ссылок повысить производительность. Хэш выполняет вычисления в массиве ulong[4], но результатом является массив 16 byte. В настоящее время я копирую массив ulong в буфер результата byte, но это занимает немного времени. Поэтому мне интересно, можно ли System.Runtime.CompilerServices.Unsafe использовать здесь:

var result = new byte[16];
ulong[] state = Unsafe.As<byte[], ulong[]>(ref result);
ref var firstState = ref state[0];
ref var secondState = ref state[1];
ulong thirdState = 0;
ulong fourthState = 0;

Вышеприведенный фрагмент кода означает, что я использую буфер результатов также для частей моих вычислений состояния, а не только для окончательного вывода.

Мои юнит-тесты успешны, и в соответствии с тестом benchmarkdotnet, пропускающим копию блока, это приведет к увеличению производительности 20%, что достаточно для меня, чтобы выяснить, правильно ли использовать его.

Ответ 1

С# поддерживает "фиксированные буферы", вот что мы можем сделать:

    public unsafe struct Bytes
    {
        public fixed byte bytes[16];
    }

затем

    public unsafe static Bytes Convert (long[] longs)
    {
        fixed (long * longs_ptr = longs)
              return *((Bytes*)(longs_ptr));
    }

Попробуйте. (1D массивы примитивных типов в С# всегда хранятся как непрерывный блок памяти, поэтому прием адреса массивов (управляемых) в порядке).

Вы также можете вернуть указатель для большей скорости:

    public unsafe static Bytes * Convert (long[] longs)
    {
        fixed (long * longs_ptr = longs)
        return ((Bytes*)(longs_ptr));
    }

и манипулировать/обращаться к байтам, как вы хотите.

        var s = Convert(longs);
        var b = s->bytes[0];