Добавление массива фиксированного размера в IEnumerable

Этот метод получает:

IEnumerable<object[]> - в котором каждый массив имеет фиксированный размер (он представляет реляционную структуру данных).

DataEnumerable.Column[] — некоторые столбцы метаданных, в основном они будут иметь одинаковое значение для всех строк.

Ожидаемый результат:

каждая «строка» должна получать значение для каждого из этих столбцов (поэтому структура данных остается реляционной).

    private IEnumerable<object[]> BindExtraColumns(IEnumerable<object[]> baseData, int dataSize, DataEnumerable.Column[] columnsToAdd)
    {
        int extraColumnsLength = columnsToAdd.Length;
        object[] row = new object[dataSize + extraColumnsLength];

        string columnName;
        int rowNumberColumnIndex = -1;

        for (int i = 0; i < extraColumnsLength; i++)
        {
            //Assign values that doesn't change between lines..
            // Assign rowNumberColumnIndex if row number column exists
        }

        //Assign values that change here, since we currently support only row number
        // i'ts not generic enough        
        if (rowNumberColumnIndex != -1)
        {
            int rowNumber = 1;

            foreach (var baseRow in baseData)
            {
                row[rowNumberColumnIndex] = rowNumber;

                Array.Copy(baseRow, 0, row, extraColumnsLength, dataSize);

                yield return row;

                rowNumber++;
            }
        }
        else
        {
            foreach (var baseRow in baseData)
            {
                Array.Copy(baseRow, 0, row, extraColumnsLength, dataSize);

                yield return row;
            }
        }
    }

этот метод можно вызывать из сотен потоков с относительно большими наборами данных, поэтому производительность здесь критична, и я старался создавать как можно меньше новых объектов.

Обратите внимание - это закрытый метод, который использует ТОЛЬКО BY DataReader, который читает каждую строку и передает ее в другой массив непосредственно перед чтением следующей строки.

Итак, здесь как-то оптимизировано копирование массивов, и должен ли я (осторожно) использовать память, чтобы ускорить работу здесь?

Спасибо


person Yosi Dahari    schedule 04.09.2013    source источник


Ответы (1)


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

List<object[]> rows = BindExtraColumns(data, size, toAdd).ToList();

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

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

Если вы действительно не хотите этого делать, я предлагаю вам изменить подход, чтобы вызывающий объект должен был передавать Action<object[]> для выполнения в каждой строке с документированной оговоркой, что если вызывающий объект хранит ссылку на массив, они вполне может быть удивлен результатами.

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

РЕДАКТИРОВАТЬ: Теперь мы знаем, что это закрытый метод, только используемый в одном конкретном месте, я бы все равно избегал повторного использования. Это просто хрупко. Я бы действительно перешел на передачу Action<object[]> или просто каждый раз копировал данные в новый массив. Я, конечно, не стал бы придерживаться текущего подхода без веских доказательств того, что он является узким местом: как я уже говорил ранее, я ожидаю, что связь с базой данных будет гораздо важнее. Оставлять бомбы замедленного действия в вашем коде очень редко бывает хорошо.

Если вы действительно, действительно хотите продолжать это делать, вам следует очень документировать это, давая строгие предупреждения о том, что результат неидиоматичен.

С точки зрения того, есть ли больше оптимизация, которую вы могли бы сделать - ну... одной из альтернатив было бы в первую очередь избегать работы с одним массивом. Вы можете создать класс, который содержит ссылки на оба массива (текущую базовую строку и фиксированные данные) и предоставляет индексатор, который возвращает значение из одного или другого массива в зависимости от запрашиваемого индекса. Мы не знаем, что вы делаете с данными ("передает их в другой массив" на самом деле ничего не значит), поэтому мы не знаем, осуществимо ли это, но это было бы эффективно и может быть реализовано без странного поведения.

person Jon Skeet    schedule 04.09.2013
comment
У меня было это беспокойство, и я написал это, как вы сказали, для начала. Но как я могу узнать/обработать ограничение памяти? И кстати - в настоящее время он работает нормально! - person Yosi Dahari; 04.09.2013
comment
@Yosi: Предположительно, в настоящее время он работает нормально из-за того, как вы случайно его используете. Это не значит, что он не слишком хрупкий. Что касается ограничения памяти - какое ограничение памяти? Вы не объяснили точно, что это за ограничение или как вы его диагностировали. - person Jon Skeet; 04.09.2013
comment
во-первых, спасибо за вашу помощь! Думаю, я понял вашу точку зрения. Мне кажется пугающим создание такого количества массивов для каждого вызова, но я думаю, что это не может быть проблемой, и наверняка независимо от того, что этот код выглядит плохо после того, что вы описали. - person Yosi Dahari; 04.09.2013
comment
@Yosi: Есть ли причина не принимать это? Не работает как-то? Если да, пожалуйста, дайте более подробную информацию. - person Jon Skeet; 08.09.2013
comment
@Yosi: Смотрите мое редактирование. До сих пор не совсем ясно, есть ли у вас какие-либо доказательства того, что производительность здесь критична — вы, конечно же, не опубликовали никаких доказательств на этот счет (подкрепленных измерением влияния копирования массива данные против влияния чтения данных для начала). - person Jon Skeet; 08.09.2013
comment
Примечание: это не мой первый вариант реализации того, что мне нужно. Более любимым решением для меня было добавить столбцы в datareader (IEnumerable в этот вопрос был создан этим DataReader) - person Yosi Dahari; 30.11.2013