У меня есть два огромных массива (int source [1000], dest [1000] в коде ниже, но в действительности есть миллионы элементов). Исходный массив содержит ряд int
из которых я хочу скопировать 3 из каждых 4.
Например, если исходный массив:
int source[1000] = {1,2,3,4,5,6,7,8....};
int dest[1000];
Вот мой код:
for (int count_small = 0, count_large = 0; count_large < 1000; count_small += 3, count_large +=4)
{
dest[count_small] = source[count_large];
dest[count_small+1] = source[count_large+1];
dest[count_small+2] = source[count_large+2];
}
В конце концов, выход консоли console будет:
1 2 3 5 6 7 9 10 11...
Но этот алгоритм настолько медленный! Есть ли алгоритм или функция с открытым исходным кодом, которую я могу использовать/включить?
Спасибо :)
Изменение: фактическая длина моего массива составит около 1 миллиона (640 * 480 * 3)
Редактирование 2: обработка этого цикла занимает от 0,98 секунды до 2,28 секунды, а другой код занимает от 0,08 секунды до 0,14 секунды, поэтому устройство использует не менее 90% времени процессора только для цикла
Вы можете попробовать memcpy
вместо отдельных назначений:
memcpy(&dest[count_small], &source[count_large], sizeof(int) * 3);
Ну, асимптотическая сложность там так же хороша, как и собираться. Возможно, вы сможете добиться немного лучшей производительности, загрузив значения в виде четырех четырехсторонних SIMD-целых чисел, перетасовывая их в три 4-позиционных SIMD-целых числа и записывая их обратно, но даже это вряд ли будет намного быстрее.
С учетом сказанного, однако, время обработки 1000 элементов (Edit: или один миллион элементов) будет совершенно тривиальным. Если вы считаете, что это узкое место в вашей программе, вы ошибаетесь.
Прежде чем делать гораздо больше, попробуйте профилировать свое приложение и определить, является ли это лучшим местом для проведения вашего времени. Затем, если это горячее пятно, определите, насколько это быстро, и как быстро вам это нужно/может достичь? Затем проверьте альтернативы; накладные расходы на потоки или OpenMP могут даже замедлить работу (особенно, как вы уже отмечали, если вы работаете на одном основном процессоре, и в этом случае это вообще не поможет). Для одиночной резьбы я бы посмотрел на memcpy
в соответствии с ответом Шона.
@Sneftel также ссылается на другие варианты ниже, содержащие SIMD-целые числа.
Один из вариантов - попытаться выполнить параллельную обработку цикла и посмотреть, поможет ли это. Вы можете попробовать использовать стандарт OpenMP (см. Ссылку Википедии здесь), но вам придется попробовать его для вашей конкретной ситуации и посмотреть, помогло ли это. Я использовал это недавно в реализации ИИ, и это очень помогло нам.
#pragma omp parallel for
for (...)
{
... do work
}
Помимо этого, вы ограничены собственными оптимизациями компилятора.
Вы также можете посмотреть недавнюю поддержку потоков в C11, хотя вам может быть лучше использовать предварительно реализованные средства инфраструктуры, такие как parallel_for
(доступны в новой среде выполнения Windows Concurrency Runtime через PPL в Visual Studio, если это то, что вы используете), чем сворачивая свои собственные.
parallel_for(0, max_iterations,
[...] (int i)
{
... do stuff
}
);
Внутри цикла for
вас все еще есть другие варианты. Вы можете попробовать цикл for, который выполняет итерацию и пропускает все, вместо того, чтобы делать 3 копии на итерацию (просто пропустите, когда (i+1) % 4 == 0
), или выполните операции блочной memcopy
для групп из 3 целых чисел в соответствии с ответом Seans, Для некоторых из них вы можете добиться немного разных оптимизаций компилятора, но это маловероятно (memcpy
, вероятно, так же быстро, как вы получите).
for (int i = 0, int j = 0; i < 1000; i++)
{
if ((i+1) % 4 != 0)
{
dest[j] = source[i];
j++;
}
}
Затем вы должны разработать испытательную установку, чтобы вы могли быстро выполнить тест производительности и выбрать лучший для вас. Прежде всего, решите, сколько времени стоит потратить на это, прежде чем оптимизировать в другом месте.
Если у вас есть карта Nvidia, вы можете использовать CUDA. Если это не так, вы можете попробовать другие методы и среды параллельного программирования.
Является ли ваш массив размером всего 1000? Если да, то как это медленно? Это должно быть сделано в кратчайшие сроки! Пока вы создаете новый массив и однопоточное приложение, это единственный удаленный AFAIK.
Однако, если массивы данных огромны, вы можете попробовать многопоточное приложение.
Также вы можете исследовать наличие более крупного типа данных, содержащего значение, так что размер массива уменьшается... То есть, если это жизнеспособно для вашего реального приложения.