用 int 乘以并添加到 C 中的 int 数组的最快方法?
Fastest way to multiply and add to an int array in C by an int?
我在用 C 编程时学习了一些关于 pthreads 和性能的知识,我想知道最好的方法是将单个 int
添加到数组中的所有元素(相当大一个大约有 5000 个元素)以及将 int
乘以数组中所有元素的最佳方法。
我尝试并行执行此操作,但没有太大改进。我的并行方法是将包含值的 struct
传递给 add/multiply 以及指向数组的指针。我将其作为参数传递给 pthread_create
。在被调用的函数中,我 added/multiplied 将给定值赋给数组中的所有元素。
我觉得好像有更好的方法可以将一个数字乘以或添加到数组中的所有 5000 个(或更多)元素。我也听说过那些 SIMD 命令。这对这种情况有帮助吗?
您必须使用分而治之的方法拆分数组。创建多个线程并为每个线程分配数组的一部分。
所以创建 5 个线程并为线程提供元素 0..999 1000..1999 ...
您不必使用多线程来解决您的问题,否则将没有性能提升。
旁注:我认为该数组太小,无法显示多线程实现比直接实现有任何改进。
如果你可以假设一个 x86 CPU 那么你可以使用英特尔的 SSE SIMD 扩展一次处理 4 个元素。
例如向数组的所有元素添加一个值:
#include "emmintrin.h"
// ...
const __m128i vinc = _mm_set1_epi32(inc); // init vector containing value to add
for (int i = 0; i < N; i += 4)
{
__m128i v = _mm_loadu_si128(&a[i]); // load 4 elements from array a
v = _mm_add_epi32(v, vinc); // add increment to each element
_mm_storeu_si128(&a[i], v); // save 4 modified elements back to a
}
在较新的 CPU 上,例如Haswell,您可以使用 AVX2 以类似的方式每次迭代处理 8 个元素。
请注意,某些编译器已经为您矢量化此代码,例如gcc、clang、ICC,甚至是 Visual Studio 的最新版本(在美好的一天),因此您甚至可能不需要使用 SSE 内在函数对此进行显式编码。
还有优化的库可以为您执行此类操作,例如Intel的IPP,或者Apple的Accelerate框架,还有很多其他的开源库。
关于过早优化的常见警告当然适用:您应该首先对现有代码进行基准测试,并确定它是性能瓶颈,然后再尝试对其进行优化。
我在用 C 编程时学习了一些关于 pthreads 和性能的知识,我想知道最好的方法是将单个 int
添加到数组中的所有元素(相当大一个大约有 5000 个元素)以及将 int
乘以数组中所有元素的最佳方法。
我尝试并行执行此操作,但没有太大改进。我的并行方法是将包含值的 struct
传递给 add/multiply 以及指向数组的指针。我将其作为参数传递给 pthread_create
。在被调用的函数中,我 added/multiplied 将给定值赋给数组中的所有元素。
我觉得好像有更好的方法可以将一个数字乘以或添加到数组中的所有 5000 个(或更多)元素。我也听说过那些 SIMD 命令。这对这种情况有帮助吗?
您必须使用分而治之的方法拆分数组。创建多个线程并为每个线程分配数组的一部分。 所以创建 5 个线程并为线程提供元素 0..999 1000..1999 ...
您不必使用多线程来解决您的问题,否则将没有性能提升。
旁注:我认为该数组太小,无法显示多线程实现比直接实现有任何改进。
如果你可以假设一个 x86 CPU 那么你可以使用英特尔的 SSE SIMD 扩展一次处理 4 个元素。
例如向数组的所有元素添加一个值:
#include "emmintrin.h"
// ...
const __m128i vinc = _mm_set1_epi32(inc); // init vector containing value to add
for (int i = 0; i < N; i += 4)
{
__m128i v = _mm_loadu_si128(&a[i]); // load 4 elements from array a
v = _mm_add_epi32(v, vinc); // add increment to each element
_mm_storeu_si128(&a[i], v); // save 4 modified elements back to a
}
在较新的 CPU 上,例如Haswell,您可以使用 AVX2 以类似的方式每次迭代处理 8 个元素。
请注意,某些编译器已经为您矢量化此代码,例如gcc、clang、ICC,甚至是 Visual Studio 的最新版本(在美好的一天),因此您甚至可能不需要使用 SSE 内在函数对此进行显式编码。
还有优化的库可以为您执行此类操作,例如Intel的IPP,或者Apple的Accelerate框架,还有很多其他的开源库。
关于过早优化的常见警告当然适用:您应该首先对现有代码进行基准测试,并确定它是性能瓶颈,然后再尝试对其进行优化。