Как переместить два счетчика одновременно? - PullRequest
0 голосов
/ 18 декабря 2018

У меня есть два больших массива двух структур readonly: A и B. Мне нужно перечислить их, но мне нужно сделать это наиболее оптимизированным способом.

readonly struct A {
   long a;
   long b;
   long c;
   long d;
   long e;
   long g;
}

readonly struct B {
   byte a;
   ushort b;
}

Как видите, тип A очень большой struct, чтобы копировать его снова и снова, поэтому я создал свой собственный перечислитель, который возвращает этот struct по ссылке (ref return).Типу B это не нужно, потому что его размер составляет всего 4 байта.Теперь мне нужно сделать так, чтобы два перечислителя перемещались одновременно, используя только один цикл foreach, потому что он не выглядит сильно нативным, вызывая методы перечислителя напрямую (т.е. MoveNext, Current) и так далее.

Моя проблема в том, что, когда я пытаюсь сохранить две структуры в одном агрегате, struct A копируется, и я теряю выигрыш в производительности.

public readonly struct Aggregate
{
    public readonly A ItemA;
    public readonly B ItemB;

    public Aggregate(A itemA, in B itemB)
    {
        ItemA = itemA;
        ItemB = itemB;
    }
}

Общий размер этого агрегата будет иметьразмер 56 байт.Звучит логично, что C # копирует структуру, когда я назначаю ее свойству другой структуры.Но что я могу с этим сделать?Мне нужна только ссылка на элемент массива.Я думаю, что использование небезопасного кода для получения указателя - неправильный путь, потому что GC может переместить мой массив (если он достаточно мал и не расположен в области LOH).

Итак, какие решения вы могли бы предложить мне?

Ответы [ 2 ]

0 голосов
/ 18 декабря 2018

Не знаю, правильно ли я понимаю ваш вопрос или нет, но вы говорите о массивах.

Предположение: Оба массива одинакового размера

Выможет сделать это

for (int i = 0; i < length; i++)
{
    ref var aItem = ref arrayA[i];
    ref var bItem = ref arrayB[i];
    //do your stuff
}
0 голосов
/ 18 декабря 2018

Вы можете использовать перечислители явно, без цикла foreach:

var aEnumerator = listA.GetEnumerator();
var bEnumerator = listB.GetEnumerator();
while (aEnumerator.MoveNext() && bEnumerator.MoveNext()) {
    var aItem = aEnumerator.Current;
    var bItem = bEnumerator.Current;
    //TODO: do some work
}
...