Ответ 1
Я бы посоветовал вам взглянуть на учебник OpenMP из Национальной лаборатории Лоуренса Ливермора, доступный здесь.
В вашем конкретном примере используется не с использованием задач OpenMP. Второй код создает N
раз число задач потоков (потому что в коде отсутствует ошибка }
, я вернусь к ней позже), и каждая задача будет выполнять очень простое вычисление. Накладные расходы задач были бы гигантскими, как вы можете видеть в моем ответе на этот вопрос. Кроме того, второй код концептуально неверен. Поскольку нет директивы об обслуживании, все потоки будут выполнять все итерации цикла и вместо N
задач, N
раз число задач нитей будет создано. Его следует переписать одним из следующих способов:
Отдельная задача производителя - общий шаблон, NUMA недружественный:
void saxpy_tasks(float* x, float* y, float a, int N) {
#pragma omp parallel
{
#pragma omp single
{
for (int i = 0; i < N; i++)
#pragma omp task
{
y[i] = y[i]+a*x[i];
}
}
}
}
Директива single
заставит цикл работать только внутри одного потока. Все остальные потоки пропустили бы его и попали в неявный барьер в конце конструкции single
. Поскольку барьеры содержат неявные точки планирования задачи, потоки ожидания сразу же начнут обрабатывать задачи по мере их появления.
Производитель параллельных задач - больше NUMA:
void saxpy_tasks(float* x, float* y, float a, int N) {
#pragma omp parallel
{
#pragma omp for
for (int i = 0; i < N; i++)
#pragma omp task
{
y[i] = y[i]+a*x[i];
}
}
}
В этом случае цикл создания задачи будет разделяться между потоками.
Если вы не знаете, что такое NUMA, игнорируйте комментарии об удобстве NUMA.