Раньше я думал, что многопоточность наиболее эффективна, когда мы выполняем блокирующие операции, и в течение этого времени мы можем продолжить выполнение других инструкций в других потоках.
Недавно я выполнил простой тест. Я создал вектор данных и разделил поровну строки между потоками и сравнил время выполнения с одним рабочим потока. Многопоточность была победителем.
Вот мой код:
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <numeric>
#include <chrono>
double g_sum = 0;
std::mutex g_mutex;
void worker(const std::vector<double>& vec)
{
const auto vectorSum = std::accumulate(vec.begin(), vec.end(), 0.0);
std::lock_guard<std::mutex> lg(g_mutex);
std::cout << "Thread-Worker adding " << vectorSum << " to final sum ("<< g_sum <<")\n";
g_sum += vectorSum;
}
int main()
{
const int ROW_SIZE = 10000000;
const int threadsSize = std::thread::hardware_concurrency();
std::cout << "Task will be seprated on " << threadsSize << " threads\n";
// data vector with row for every thread
std::vector<std::vector<double>> dataVector;
double fillVal = 1.1;
for (auto i = 0; i < threadsSize; ++i, fillVal += 1.1)
{
dataVector.push_back(std::vector<double>(ROW_SIZE, fillVal));
}
std::vector<std::thread> threadContainer;
auto start = std::chrono::system_clock::now();
for (const auto& row : dataVector)
{
std::thread thread(&worker, std::ref(row));
threadContainer.push_back(std::move(thread));
}
for (auto& thread : threadContainer)
{
thread.join();
}
auto end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::cout << "threads time: " << elapsed_seconds.count() << "s\n";
// main thread only
g_sum = 0;
start = std::chrono::system_clock::now();
for (const auto& row : dataVector)
{
const auto vectorSum = std::accumulate(row.begin(), row.end(), 0.0);
std::cout << "Main Thread adding " << vectorSum << " to final sum ("<< g_sum <<")\n";
g_sum += vectorSum;
}
end = std::chrono::system_clock::now();
elapsed_seconds = end-start;
std::cout << "one-thread time: " << elapsed_seconds.count() << "s\n";
}
в wandbox (https://wandbox.org/permlink/qah5auBI3ZoAe7B2) с 3 логическими ядрами, результаты синхронизации многопоточности в два раза лучше чем однопоточность.
Мой тест правильный? Могу ли я предположить, что, пропуская дополнительное время реализации, разделение рабочей задачи между потоками всегда лучший выбор?