Список <struct []>. Добавить против списка <строка []>. Добавить или Список <объект []>. Добавить производительность - PullRequest
0 голосов
/ 17 ноября 2011

У меня есть код, который добавляет в список ~ 100 000 элементов.

Если я добавляю массив строк или объектов, код запускается практически мгновенно (менее 100 мс), но если я пытаюсь добавить массив структур, это займет почти 1,5 секунды только для вызовов .Add.

Почему при использовании struct [] наблюдается такое влияние на производительность?

Вот моя структура:

public struct LiteRowInfo
{
    public long Position;
    public int Length;
    public int Field;
    public int Row;

    public LiteRowInfo(long position, int length, int field, int row)
    {
        this.Position = position;
        this.Length = length;
        this.Field = field;
        this.Row = row;
    }
}

РЕДАКТИРОВАТЬ 2: Производительность строкового метода быстрее, чем у структуры: Я ценю комментарии, кажется, что есть дополнительные издержки при создании структуры как таковой. Я думаю, что я просто создам 2 отдельных списка для хранения позиции и длины, чтобы улучшить производительность.

private void Test()
    {
        Stopwatch watch = new Stopwatch();

        watch.Start();
        List<LiteRowInfo[]> structList = new List<LiteRowInfo[]>();

        for (int i = 0; i < 100000; i++)
        {
            LiteRowInfo[] info = new LiteRowInfo[20];

            for (int x = 0; x < 20; x++)
            {
                LiteRowInfo row;
                row.Length = x;
                row.Position = (long)i;
                info[x] = row;
            }
            structList.Add(info);
        }
        Debug.Print(watch.ElapsedMilliseconds.ToString());

        watch.Reset();
        watch.Start();

        List<string[]> stringList = new List<string[]>();

        for (int i = 0; i < 100000; i++)
        {
            string[] info = new string[20];

            for (int x = 0; x < 20; x++)
            {
                info[x] = "String";
            }
            stringList.Add(info);
        }

        Debug.Print(watch.ElapsedMilliseconds.ToString());
    }

РЕДАКТИРОВАТЬ: Вот весь соответствующий код: Примечание: если я закомментирую только pos.Add (rowInfo); строка, производительность аналогична производительности строки [] или int [].

        private void executeSqlStream()
    {
        List<LiteRowInfo[]> pos = new List<LiteRowInfo[]>();

        long currentPos = 0;

        _stream = new MemoryStream();
        StreamWriter writer = new StreamWriter(_stream);

        using (SqlConnection cnn = new SqlConnection(_cnnString))
        {
            cnn.Open();
            SqlCommand cmd = new SqlCommand(_sqlString, cnn);

            SqlDataReader reader = cmd.ExecuteReader();

            int fieldCount = reader.FieldCount;
            int rowNum = 0;
            UnicodeEncoding encode = new UnicodeEncoding();
            List<string> fields = new List<string>();
            for (int i = 0; i < fieldCount; i++)
            {
                fields.Add(reader.GetFieldType(i).Name);
            }
            while (reader.Read())
            {
                LiteRowInfo[] rowData = new LiteRowInfo[fieldCount];
                for (int i = 0; i < fieldCount; i++)
                {
                    LiteRowInfo info;
                    if (reader[i] != DBNull.Value)
                    {
                        byte[] b;
                        switch (fields[i])
                        {
                            case "Int32":
                                b = BitConverter.GetBytes(reader.GetInt32(i));
                                break;
                            case "Int64":
                                b = BitConverter.GetBytes(reader.GetInt64(i));
                                break;
                            case "DateTime":
                                DateTime dt = reader.GetDateTime(i);
                                b = BitConverter.GetBytes(dt.ToBinary());
                                break;
                            case "Double":
                                b = BitConverter.GetBytes(reader.GetDouble(i));
                                break;
                            case "Boolean":
                                b = BitConverter.GetBytes(reader.GetBoolean(i));
                                break;
                            case "Decimal":
                                b = BitConverter.GetBytes((float)reader.GetDecimal(i));
                                break;
                            default:
                                b = encode.GetBytes(reader.GetString(i));
                                break;
                        }
                        int len = b.Length;

                        info.Position = currentPos += len;
                        info.Length = len;
                        info.Field = i;
                        info.Row = rowNum;
                        currentPos += len;
                        _stream.Write(b, 0, len);
                    }
                    else
                    {
                        info.Position = currentPos;
                        info.Length = 0;
                        info.Field = i;
                        info.Row = rowNum;
                    }
                    rowData[i] = info;
                }
                rowNum++;
                pos.Add(rowData);
            }
        }
    }

Ответы [ 2 ]

8 голосов
/ 17 ноября 2011

Учитывая, что сам массив является ссылочным типом, я очень сомневаюсь, что вы на самом деле видите то, что, как вы думаете, вы видите.

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

Для сравнения просто List<T>.Add, я предлагаю вам несколько раз добавлять ссылку на один и тот же массив несколько раз.

Кроме того, наличие массива в качестве типа элемента списка для меня немного неприятно. Бывают моменты, когда это действительно так, но лично я бы подумал, может ли это быть чем-то, что может быть инкапсулировано в другом типе.

РЕДАКТИРОВАТЬ: Вы говорите, что вы опубликовали весь соответствующий код, но действительно не является эталонным кодом для List<T>.Add - он содержит доступ к базе данных с одной стороны, что почти наверняка займет путь дольше, чем любая из манипуляций в памяти!

0 голосов
/ 17 ноября 2011

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

...