Как организовать пул не поточно-ориентированных ресурсов в Cilk Plus (один ресурс на одного работника)?

У меня есть последовательный код, который я хотел бы распараллелить, используя Cilk Plus; основной цикл повторно вызывает функцию обработки для разных наборов данных, поэтому итерации не зависят друг от друга, за исключением использования не поточно-ориентированного ресурса, который инкапсулируется в класс (скажем, nts) предоставляется внешней библиотекой, которая принимает имя файла и выполняет для него ввод-вывод.

Если бы я использовал OpenMP, я бы создал пул ресурсов, который содержит столько ресурсов, сколько у меня потоков, и получал бы доступ к этим ресурсам в соответствии с идентификатором потока:

std::vector<nts> nts_pool;
for (std::size_t i{0}; i < omp_get_num_threads(); ++i)
nts_pool.push_back(nts{});

nts_pool[omp_get_thread_num()].do_stuff();  // from inside the task

Используя Cilk Plus, я мог бы сделать столько же, используя __cilkrts_get_nworkers() а также __cilkrts_get_worker_number() API, но из нескольких постов на форумах Intel я понял, что это считается неправильным решением проблемы, и правильным решением было бы использование гиперобъекта-держателя.

Теперь решение для держателя выглядит действительно хорошо, за исключением того, что я действительно хочу, чтобы было создано только столько представлений, сколько у меня есть рабочих потоков. То есть для 3-х рабочих потоков мне бы хотелось иметь 3 объекта и не более. Обоснование состоит в том, что, как я уже сказал, ресурс предоставляется сторонней библиотекой, его создание очень дорого, и мне придется иметь дело с получающимися файлами впоследствии, поэтому чем меньше, тем лучше.

К сожалению, я обнаружил, что вместо того, чтобы делать представление для каждого работника и сохранять его до синхронизации, владельцы каким-то образом создают и уничтожают представления в соответствии с логикой, которую я не понимаю, и, похоже, нет способа повлиять это поведение.

Можно ли заставить держателей вести себя так, как я хочу, и если нет, то каким будет идиоматическое решение Cilk Plus для моей проблемы?

Вот программа, которую я использовал для исследования владельцев, обратите внимание, что она создает до 50 просмотров на моей тестовой машине за один прогон, которые распределяются и уничтожаются, казалось бы, наугад:

#include <iostream>
#include <atomic>

#include <cilk/cilk.h>
#include <cilk/holder.h>
#include <cilk/reducer_ostream.h>
#include <cilk/cilk_api.h>

cilk::reducer_ostream *hyper_cout;

class nts {
public:
nts() : tag_{std::to_string(++id_)} {
*hyper_cout << "NTS constructor: " << tag_ << std::endl;
}
~nts() {
*hyper_cout << "NTS destructor: " << tag_ << std::endl;
}
void print_tag() {
*hyper_cout << "NTS tag: " << tag_ << std::endl;
}
static void is_lock_free() {
*hyper_cout << "Atomic is lockfree: " << id_.is_lock_free() << std::endl;
}
private:
const std::string tag_;
static std::atomic_size_t id_;
};

std::atomic_size_t nts::id_{0};

class nts_holder {
public:
void print_tag() { nts_().print_tag(); }
private:
cilk::holder<nts> nts_;
};

int main() {

__cilkrts_set_param("nworkers", "4");

cilk::reducer_ostream cout{std::cout};
hyper_cout = &cout;

*hyper_cout << "Workers: " <<  __cilkrts_get_nworkers() << std::endl;
nts::is_lock_free();

nts_holder ntsh;
ntsh.print_tag();

for (std::size_t i{0}; i < 1000; ++i) {
cilk_spawn [&] () {
ntsh.print_tag();
} ();
}

cilk_sync;

return 0;

}

1

Решение

Вы правы, что владельцы являются заманчивым, но неэффективным решением этой конкретной проблемы. Если ваша программа работает правильно, используя массив слотов с одним слотом на одного работника, то в действительности нет ничего плохого в использовании __cilkrts_get_nworkers() а также __cilkrts_get_worker_number() API в этом случае. Мы не одобряем их использование в целом; предпочитая писать код Cilk Plus, который не учитывает число работников, потому что таким образом он обычно масштабируется лучше. Однако в некоторых случаях, в том числе и в этом, создание слота на одного работника является наилучшей стратегией.

1

Другие решения


По вопросам рекламы [email protected]