Я работаю над проектом, который использует несколько потоков для распараллеливания задач. Во время разработки я заметил, что производительность операций с контейнером std :: list, например pop_front () или push_back (), значительно медленнее при выполнении в потоке по сравнению с выполнением в одном потоке. См. Фрагмент кода ниже:
#include <iostream>
#include <chrono>
#include <vector>
#include <string>
#include <thread>
#include <list>
using namespace std;
void SingleThreadedList()
{
auto t1 = std::chrono::high_resolution_clock::now();
for(int i=0; i<2; i++)
{
list<char> l;
for(int j=0; j<10000; j++)
{
l.push_back('c');
l.pop_front();
}
}
auto t2 = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();
std::cout << "duration single thread: " << duration << endl;
}
void MultiThreadedList()
{
auto t1 = std::chrono::high_resolution_clock::now();
auto lambda_fkt = []() {
list<char> l;
for(int i=0; i<10000; i++)
{
l.push_back('c');
l.pop_front();
}
};
vector<thread*> thread_array;
for (int i=0; i<2; ++i)
{
thread *th = new thread(lambda_fkt);
thread_array.push_back(th);
}
for(auto t : thread_array)
{
t->join();
}
auto t2 = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();
std::cout << "duration multi thread: " << duration << endl;
for(auto t : thread_array)
{
delete t;
}
}
int main() {
SingleThreadedList();
MultiThreadedList();
}
код дает следующий результат:
duration single thread: 4589
duration multi thread: 245483
Вариант с одним потоком занимает 4 мс, но как только потоки созданы, выполнение занимает больше чем 200 мс! Я не могу представить, чтобы стандартные библиотечные контейнеры показывали такую разницу в производительности в зависимости от контекста выполнения. Поэтому мне интересно, может ли кто-нибудь объяснить мне, что происходит в этом коде и как я могу избежать снижения производительности в пределах thread
? Спасибо!
PS: Когда я удаляю операции со списком из этого примера и добавляю, например, некоторую простую математику, код быстро показывает ожидаемое поведение: многопоточный вариант становится быстрее, если вычисление разделено между несколькими потоками , таким образом используя несколько ядер для получения результата.