Written on
·
242
1
아무리 봐도 코드 오류가 잘 안보이네요,
어느부분이 잘못되었는지 짚어주실수 있을까요?
#include <iostream>
#include <thread>
#include <mutex>
#include <utility>
#include <vector>
#include <atomic>
#include <chrono>
#include <numeric>
#include <random>
#include <execution>
#include <future>
using namespace std;
auto dotProductNaive(const vector<int>& v0, const vector<int>& v1,
const unsigned i_start, const unsigned i_end, unsigned long long & sum)
{
for(unsigned i = i_start; i < i_end; ++i)
sum += v0[i] * v1[i];
return sum;
}
mutex mtx;
auto dotProductLock(const vector<int>& v0, const vector<int>& v1,
const unsigned i_start, const unsigned i_end, unsigned long long & sum)
{
for(unsigned i = i_start; i < i_end;++i)
{
std::scoped_lock lock(mtx); //c++17
sum += v0[i] * v1[i];
}
return sum;
}
auto dotProductAtomic(const vector<int>& v0, const vector<int>& v1,
const unsigned i_start, const unsigned i_end, atomic<unsigned long long>& sum)
{
for(unsigned i = i_start; i < i_end;++i)
{
sum += v0[i] * v1[i];
}
}
auto dotProductFuture(const vector<int>& v0, const vector<int>& v1,
const unsigned i_start, const unsigned i_end)
{
int sum = 0;
for(unsigned i=i_start; i<i_end; ++i)
{
sum += v0[i] * v1[i];
}
return sum;
}
int main()
{
const long long n_data = 100'000'000;
const unsigned n_threads = 4;
//init vectors
std::vector<int> v0, v1;
v0.reserve(n_data);
v1.reserve(n_data);
random_device seed;
mt19937 engine(seed());
uniform_int_distribution<> uniformDist(1, 10);
for(long long i = 0; i < n_data; ++i)
{
v0.push_back(uniformDist(engine));
v1.push_back(uniformDist(engine));
}
cout << "std::inner_product" << endl;
{
const auto sta = chrono::steady_clock::now();
const auto sum = std::inner_product(v0.begin(), v0.end(), v1.begin(), 0ull);//unsigned long long
const chrono::duration<double> dur = chrono::steady_clock::now() - sta;
cout << dur.count() << endl;
cout << sum << endl;
cout << endl;
}
// cout << "Naive" << endl;
// {
// const auto sta = std::chrono::steady_clock::now();
// std::vector<thread> threads;
// threads.resize(n_threads);
// const unsigned n_per_thread = n_data / n_threads;
// unsigned long long sum = 0;
// for(unsigned t = 0; t < n_threads; ++t)
// {
// threads[t] = std::thread(dotProductNaive, std::ref(v0),
// std::ref(v1), t*n_per_thread, (t+1)*n_per_thread, std::ref(sum));
// }
// for(unsigned t = 0; t < n_threads; ++t)
// threads[t].join();
// const auto dur = std::chrono::steady_clock::now() - sta;
// cout << dur.count() << endl;
// cout << sum << endl;
// cout << endl;
// }
// cout << "Lock Guard" << endl;
// {
// const auto sta = std::chrono::steady_clock::now();
// unsigned long long sum = 0;
// std::vector<thread> threads;
// threads.resize(n_threads);
// const unsigned n_per_thread = n_data / n_threads;
// for(unsigned t = 0; t < n_threads; ++t)
// {
// threads[t] = std::thread(dotProductLock, std::ref(v0),
// std::ref(v1), t*n_per_thread, (t+1)*n_per_thread, std::ref(sum));
// }
// for(unsigned t = 0; t < n_threads; ++t)
// threads[t].join();
// const chrono::duration<double> dur = std::chrono::steady_clock::now() - sta;
// cout << dur.count() << endl;
// cout << sum << endl;
// cout << endl;
// }
// cout << "Atomic" << endl;
// {
// const auto sta = std::chrono::steady_clock::now();
// atomic<unsigned long long> sum = 0;
// std::vector<thread> threads;
// threads.resize(n_threads);
// const unsigned n_per_thread = n_data / n_threads;
// for(unsigned t = 0; t < n_threads; ++t)
// {
// threads[t] = std::thread(dotProductAtomic, std::ref(v0),
// std::ref(v1), t*n_per_thread, (t+1)*n_per_thread, std::ref(sum));
// }
// for(unsigned t = 0; t < n_threads; ++t)
// threads[t].join();
// const chrono::duration<double> dur = chrono::steady_clock::now() - sta;
// cout << dur.count() << endl;
// cout << sum << endl;
// cout << endl;
// }
// cout << "Future" << endl;
// {
// const auto sta = chrono::steady_clock::now();
// unsigned long long sum = 0;
// vector<std::future<int>> futures;
// futures.resize(n_threads);
// const unsigned n_per_threads = n_data / n_threads;
// for(unsigned t=0; t<n_threads; ++t)
// {
// futures[t] = std::async(dotProductFuture, std::ref(v0), std::ref(v1),
// t*n_per_threads, (t+1)*n_per_threads);
// }
// for(unsigned t=0; t<n_threads; ++t)
// sum += futures[t].get();
// const chrono::duration<double> dur = chrono::steady_clock::now() - sta;
// cout << dur.count() << endl;
// cout << sum << endl;
// cout << endl;
// }
cout << "std::transform_reduce" << endl;
{
const auto sta = chrono::steady_clock::now();
const auto sum = std::transform_reduce(std::execution::par, v0.begin(), v0.end(), v1.begin(), 0ull);
const chrono::duration<double> dur = chrono::steady_clock::now() - sta;
cout << dur.count() << endl;
cout << sum << endl;
cout << endl;
}
return 0;
}
Answer 1
1
안녕하세요, 답변 도우미 Soobak 입니다.
첨부해주신 코드를 그대로 컴파일 후 실행해보았습니다만, 결과는 정확하게 나오네요.
코드 또한 꼼꼼히 살펴보았지만, inner_product
의 값과 std::transform_reduce
의 값이 달라질만한 경우를 찾지 못하였습니다. 🥲
따라서, 질문자님의 환경 혹은 출력 결과 등의 추가적인 정보를 제공해주셔야 제가 문제에 대해 더 잘 인식하고 답변을 도와드릴 수 있을 것 같습니다.
안녕하세요, 답변 도우미 Soobak 입니다.
어떠한 이유에서인지, 오버플로우 문제가 발생하는 것 같네요.
아마도, VsCode
에서 사용하시는 컴파일러의 버전에 따른 라이브러리 구현 문제 같습니다.std::transform_reduce
의 초깃값은 0ull
으로 전달해주었지만, 만약 중간 계산에서 int
자료형의 임시값을 사용한다면 오버플로우가 발생할 수도 있을 것 같습니다.
선언하신 v0
과 v1
벡터의 자료형을 unsigned long long
으로 변경하신 후 컴파일해보시거나, 아래와 같이 비교 함수를 직접 전달하여 실행해보신 후 확인해보시면 좋을 것 같습니다.
(std::transform_reduce
함수의 연산 중 곱셈 연산에서 int
자료형을 전달 받더라도 unsigned long long
의 결과값을 반환하도록 변경하도록 람다 함수를 전달합니다.)
const auto sum = std::transform_reduce(
std::execution::par,
v0.begin(),
v0.end(),
v1.begin(),
0ull,
std::plus<>(),
[](int a, int b) { return static_cast<unsigned long long>(a) * b; }
);
혹은, 한 번 다른 컴파일러로 컴파일해보신 후 실행 결과를 알려주시면 어떤 부분이 문제인지 정확히 알 수 있을 것 같습니다. 🥲
저는 현재 vscode에서 c/c++ 빌드환경을 세팅해두고 예제를 풀어보고 있습니다.
아래는 위 코드 그대로 컴파일 후 나오는 터미널 메시지입니다.
transform_reduce의 결과값이 전혀 이상한 값으로 나오고 있는데 원인을 잘 모르겠어요. 무엇이 원인일까요?