Многопоточность C более длительное выполнение, чем в одном потоке

#c #multithreading

#c #многопоточность

Вопрос:

Я пытаюсь написать фрагмент кода, который проходит цикл из 8 ^ 12 итераций, и на каждой итерации, когда выполняются некоторые условия, я возвращаю push_back к вектору (у каждого потока есть свой собственный вектор для push_back, который я объединяю после цикла). Но кажется, что мое выполнение занимает больше времени, чем больше потоков активно. Здесь’ функция (метод объекта) передается в каждый поток:

 void HamiltonianKH::mapping_kernel(ull_int start, ull_int stop, std::vector<ull_int>* map_threaded, int _id) {
int n = 1;
out << "A new thread joined tha party! from " << start << " to " << stop << endl;
for (ull_int j = start; j < stop; j  ) {
    int bSz = 0, fSz = 0, N_e = 0;
    std::tie(bSz, fSz, N_e) = calculateSpinElements(this->L, j);
    if ((bSz   fSz == this->Sz) amp;amp; N_e == this->num_of_electrons) 
         map_threaded->push_back(j);
    if (show_system_size_parameters == true amp;amp; (j - start) % ull_int((stop - start) * n / 4) == 0 amp;amp; j > 0) { 
        out << n << "-th quarter of " << _id << endl; 
        n  ; 
    }
}
  

}
, вот функция caulculate_spinelements:

 std::tuple<int, int, int> calculateSpinElements(int L, ull_intamp; j) {
int bSz = 0; //bosonic total spin - spin of upper orbital locked to n=1 filling
int fSz = 0; //fermionic total spin
int N_e = 0; // numer of electrons in given state
std::vector<int> temp = int_to_binary(j, L);

for (int k = 0; k < L; k  ) {
    if (temp[k] < 4) bSz  = 1;
    else bSz -= 1;
    if (temp[k] % 4 == 1) {
        fSz  = 1;
        N_e  = 1;
    }
    else if (temp[k] % 4 == 2) {
        fSz -= 1;
        N_e  = 1;
    }
    else if (temp[k] % 4 == 3)
        N_e  = 2;
}

return std::make_tuple(bSz, fSz, N_e);
  

}

и это разделение на потоки:

 void HamiltonianKH::generate_mapping() {
ull_int start = 0, stop = std::pow(8, L);
//mapping_kernel(start, stop, mapping, L, Sz, num_of_electrons);
//Threaded
std::vector<std::vector<ull_int>*> map_threaded(num_of_threads);
std::vector<std::thread> threads;
threads.reserve(num_of_threads);
for (int t = 0; t < num_of_threads; t  ) {
    start = t * (ull_int)std::pow(8, L) / num_of_threads;
    stop = ((t   1) == num_of_threads ? (ull_int)std::pow(8, L) : (ull_int)std::pow(8, L) * (t   1) / num_of_threads);
    map_threaded[t] = new std::vector<ull_int>();
    threads.emplace_back(amp;HamiltonianKH::mapping_kernel, this, start, stop, map_threaded[t], t);
}
for (autoamp; t : threads) t.join();
for (autoamp; t : threads) t.~thread();

ull_int size = 0;
for (autoamp; t : map_threaded) {
    size  = t->size();
}

out << "size = " << size << endl;
for (auto amp; t : map_threaded)
    mapping->insert(mapping->end(), t->begin(), t->end());
//sort(mapping->begin(), mapping->end());
if (show_system_size_parameters == true) {
    out << "Mapping generated with  " << mapping->size() << "  elements" << endl;
    out << "Last element = " << mapping->at(mapping->size() - 1) << endl;
}
//out << mapping[0] << " " << mapping[mapping.size() - 1] << endl;
assert(mapping->size() > 0 amp;amp; "Not possible number of electrons - no. of states < 1");
  

}

Переменные: mapping, L, num_of_electrons и Sz являются общедоступными полями в объекте. Весь код содержит более 2000 строк, но выполнение после вызова generate_mapping() не имеет отношения к проблеме.

У кого-нибудь из вас, ребята, есть идея, почему этот фрагмент кода выполняется дольше в большем количестве потоков?

Заранее большое вам спасибо.

Комментарии:

1. Выделение памяти синхронизировано, поэтому все это push_back стоит вам.

2. Вы ни в коем случае не должны явно уничтожать свои потоки. Они будут уничтожены вектором, которому они принадлежат.

3. Да, но однопоточный и многопоточный вызовы push_back одинаковое количество раз, поэтому я не думаю, что push_back так сильно замедляет этот код:

4. один поток: 12 секунд выполнения 8 потоков: 50 секунд выполнения

5. «Да, но однопоточный и многопоточный вызовы push_back одинаковое количество раз, поэтому я не думаю, что push_back так сильно замедляет этот код» — Блокировка мьютекса в кэше уровня 1 отдельного процессора намного быстрее, чем блокировка мьютекса в общем кэше уровня 3.