Небезопасная производительность C #, удалить длинные приведения к int для доступа к индексу массива - PullRequest
4 голосов
/ 20 января 2011

Привет, я получил следующий код в C # небезопасно, где массив исправлен

array[(int)(index)]

индекс длинный (и должен быть длинным по ряду причин) .. поэтому мне нужно привести его к типу int, чтобы получить доступ к элементу массива. Есть ли способ использовать указатели или некоторую другую комбинацию действий в небезопасном коде, чтобы предотвратить это, например, индекс приведения может иметь длинное значение 1 (и никогда не превышает int value obv) .. Я чувствую, что, возможно, небезопасное добавление указателей может помешать этому. Я также чувствую, что этот актерский состав не бесплатен ... и производительность - проблема здесь. (именно эта строка) Я также думаю, что это невозможно, но я спрашиваю на всякий случай, если я ошибаюсь.

Хорошо, давайте немного подробнее, я делаю некоторые необходимые логические операции с длинным прединдексом, например

value = array [(int) ((preIndex & mask) >> 10)]

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

Спасибо

Ответы [ 5 ]

3 голосов
/ 20 января 2011

В контексте unchecked (по умолчанию) приведение просто отбрасывает ненужные MSB, поэтому не снижается производительность.В проверенном контексте будет выдано исключение, если диапазон индекса превышает int.MaxValue.

2 голосов
/ 20 января 2011

Да, есть тривиальная стоимость, конвертируемая из long в int, но я очень уверен, что: это не будет иметь значения в любом здравом коде b: это неизбежно (доступ к массивам осуществляется через индекс int; точка). Чтобы показать, что не имеет значение:

static class Program
{
    static int GetSize() { return 10000; }
    static void Main() {

        int size = GetSize();
        int[] someData = new int[size];

        var watchInt32 = Stopwatch.StartNew();
        for (int i = 0; i < 5000; i++)
        {
            for (int j = 0; j < size; j++)
            {
                someData[j]++;
            }
        }
        for (int j = 0; j < size; j++) someData[j] = 0;
        watchInt32.Stop();
        long lSize = size;
        var watchInt64 = Stopwatch.StartNew();
        for (int i = 0; i < 5000; i++)
        {
            for (long j = 0; j < lSize; j++)
            {
                someData[j]++;
            }
        }
        watchInt64.Stop();

        Console.WriteLine("{0}ms vs {1}ms over {2} iterations",
            (int)watchInt32.ElapsedMilliseconds,
            (int)watchInt64.ElapsedMilliseconds, 5000 * size);
    }
}

Я получаю:

162 мс против 215 мс при 50000000 итераций

Так что, если ваш код не выполняет ничего , кроме доступа к массиву, это просто не имеет значения. Совсем. Любым значительным образом.

1 голос
/ 20 января 2011

Я не думаю, что вам нужно беспокоиться о возможном влиянии на производительность из-за преобразования.Достаточно взглянуть на машинный код, сгенерированный JIT, они идентичны как для int, так и для индекса long:

x86, режим разблокировки, int index:

        var val = arr[idx];
00000059  cmp         ebx,dword ptr [edx+4] 
0000005c  jae         00000078 
0000005e  mov         esi,dword ptr [edx+ebx*4+8] 


x86, режим выпуска, приведенный long индекс:

        var val = arr[(int)idx];
0000005f  cmp         ebx,dword ptr [edx+4] 
00000062  jae         00000081 
00000064  mov         esi,dword ptr [edx+ebx*4+8]

x64, режим выпуска, int индекс:

        var val = arr[idx];
00000060  movsxd      rcx,ebx 
00000063  mov         rax,qword ptr [rdi+8] 
00000067  cmp         rcx,3 
0000006b  jae         0000000000000080 
0000006d  mov         ecx,dword ptr [rdi+rcx*4+10h] 


x64, выпускmode, long index:

        var val = arr[(int)idx];
00000061  movsxd      rcx,ebx 
00000064  mov         rax,qword ptr [rdi+8] 
00000068  cmp         rcx,3 
0000006c  jae         0000000000000080 
0000006e  mov         ecx,dword ptr [rdi+rcx*4+10h]

Как отметил Даниэль Геригер, инструкцию conv.i4 IL не нужно учитывать в машинном коде, 32 MSB просто отбрасываются.

0 голосов
/ 20 января 2011
int count = 10000000;
            object [] a = new object[count];

            Stopwatch s1 = Stopwatch.StartNew();
            for (long i = 0; i < count; i++)
                a[i] = new object();
            s1.Stop();

            Stopwatch s2 = Stopwatch.StartNew();
            for (int i = 0; i < count; i++)
                a[i] = new object();
            s2.Stop();       



            Debug.WriteLine(s1.ElapsedTicks + "  " + s2.ElapsedTicks);

3362502 3115428

Значительного влияния нет.

0 голосов
/ 20 января 2011

Проблема производительности, которую вы видите в этой строке, связана с поиском по индексу - это обычный массив, например, объект []?или вы реализовали свойство index?

...