我正在尝试并行化一段代码,该代码将复数浮点数的两个向量相乘并对结果求和。要做到这一点,我试图使用std :: async与期货。我的想法是将矢量分成8个部分并对这8个部分中的每个部分进行并行处理,然后将它们相加作为我的最终结果。为此,我创建8个期货,每个期货包含一个lambda,它将两个向量相乘并对结果求和。每个未来都会传递指向矢量不同位置的指针,这些位置代表了这个特定未来应该采取行动的矢量部分。
然而它似乎没有给我我预期的速度提升,它可能会加速这部分代码增加20-30%,但就是这样,此外负载似乎并没有扩散到我的核心(4或8有超线程),但似乎都是在100%的核心上。
我已经包含了以下代码。任何建议都将不胜感激。
size_t size = Input1.size()/8;
std::vector<std::future<complex<float> > > futures;
futures.reserve(8);
for(int i = 0; i<8; ++i)
{
futures.push_back(std::async( [](complex<float>* pos, complex<float>*pos2, size_t siz)
{
complex<float> resum(0,0);
for(int i = 0; i < siz; ++i)
resum += pos[i]*pos2[i];
return resum;
}, &Input1[i*size], &Input2[i*size], size));
}
complex<float> ResSum(0,0);
for(int i = 0; i < futures.size(); ++i)
ResSum += futures.at(i).get();
答案 0 :(得分:1)
如上所述,对std::async
的调用获得了launch::any
的默认启动策略,该策略允许在单个线程上运行所有异步。要坚持使用单独的线程,请将launch::async
作为std::async
调用中的第一个参数传递。
答案 1 :(得分:1)
这取决于你扔多少数据。
在以下示例中,通过简单的循环,4096个条目将更快。但是,对于1000 * 4096条目,并行版本更快。
因此,你所提出的20-30%的改善结果可能恰好落在该范围之间。
这是我使用的测试程序。
第一次运行是简单循环,第二次运行来自问题,第三次使用std::launch::async
。
Plain From With
loop question launch::async
First Second Third
166 1067 607
166 614 434
166 523 509
265993 94633 66231
182981 60594 69537
237767 65731 57256
这是live result。
#include <vector>
#include <thread>
#include <future>
#include <complex>
#include <string>
#include <iostream>
#include <chrono>
#include <random>
#include <ratio>
float get_random()
{
static std::default_random_engine e;
static std::uniform_real_distribution<> dis(0,1); // rage 0 - 1
return static_cast<float>(dis(e));
}
void do_tests(float val1, float val2, float val3, float val4, int multiplier)
{
{
std::vector<std::complex<float>> Input1(4096*multiplier,std::complex<float>{val1,val2});
std::vector<std::complex<float>> Input2(4096*multiplier,std::complex<float>{val3,val4});
std::complex<float> ResSum(0,0);
auto start{std::chrono::high_resolution_clock::now()};
size_t size = Input1.size();
for (int i=0; i<size; ++i) {
ResSum += Input1[i]*Input2[i];
}
auto end{std::chrono::high_resolution_clock::now()};
auto time_used{end-start};
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(time_used).count() << "\t\t";
}
{
std::vector<std::complex<float>> Input1(4096*multiplier,std::complex<float>{val1,val2});
std::vector<std::complex<float>> Input2(4096*multiplier,std::complex<float>{val3,val4});
std::complex<float> ResSum(0,0);
auto start{std::chrono::high_resolution_clock::now()};
size_t size = Input1.size()/8;
std::vector<std::future<std::complex<float>>> futures;
futures.reserve(8);
for (int i = 0; i<8; ++i) {
futures.push_back(
std::async(
[](std::complex<float>* pos,std::complex<float>*pos2,size_t siz) {
std::complex<float> resum(0,0);
for (int i = 0; i < siz; ++i)
resum += pos[i]*pos2[i];
return resum;
}
,&Input1[i*size],&Input2[i*size],size
)
);
}
for (int i = 0; i < futures.size(); ++i)
ResSum += futures.at(i).get();
auto end{std::chrono::high_resolution_clock::now()};
auto time_used{end-start};
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(time_used).count() << "\t\t";
}
{
std::vector<std::complex<float>> Input1(4096*multiplier,std::complex<float>{val1,val2});
std::vector<std::complex<float>> Input2(4096*multiplier,std::complex<float>{val3,val4});
std::complex<float> ResSum(0,0);
auto start{std::chrono::high_resolution_clock::now()};
size_t size = Input1.size()/8;
std::vector<std::future<std::complex<float>>> futures;
futures.reserve(8);
for (int i = 0; i<8; ++i) {
futures.push_back(
std::async(std::launch::async,
[](std::complex<float>* pos,std::complex<float>*pos2,size_t siz) {
std::complex<float> resum(0,0);
for (int i = 0; i < siz; ++i)
resum += pos[i]*pos2[i];
return resum;
}
,&Input1[i*size],&Input2[i*size],size
)
);
}
for (int i = 0; i < futures.size(); ++i)
ResSum += futures.at(i).get();
auto end{std::chrono::high_resolution_clock::now()};
auto time_used{end-start};
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(time_used).count() << "\t\t";
}
std::cout << '\n';
}
int main()
{
float val1{get_random()};
float val2{get_random()};
float val3{get_random()};
float val4{get_random()};
std::cout << "First\t\tSecond\t\tThird\n";
do_tests(val1, val2, val3, val4, 1);
do_tests(val1, val2, val3, val4, 1);
do_tests(val1, val2, val3, val4, 1);
do_tests(val1, val2, val3, val4, 1000);
do_tests(val1, val2, val3, val4, 1000);
do_tests(val1, val2, val3, val4, 1000);
}