Это довольно просто
// sum all points
// for every point
for (int i = 0; i < numObjs; ++i) {
// which cluster is it in?
int activeCluster = clusterAssignmentCurrent[i];
// update count of members in that cluster
++clusterMemberCount[activeCluster];
// sum point coordinates for finding centroid
#pragma omp parallel for
for (int j = 0; j < numCoords; ++j)
clustersCentroID[activeCluster*numCoords + j] += dataSetMatrix[i*numCoords + j];
}
Внутренний цикл идеально подходит для распараллеливания, поскольку все записи происходят с различными элементами clustersCentroID
.Вы можете с уверенностью предположить, что в расписании по умолчанию не будет значительного ложного обмена, обычно оно имеет достаточно большие фрагменты.Просто не попробуйте что-то вроде schedule(static,1)
.
Внешний цикл не так легко распараллелить.Вы можете использовать сокращение на clusterMemberCount
и clusterMemberCount
или сделать что-то вроде:
#pragma omp parallel // note NO for
for (int i = 0; i < numObjs; ++i) {
int activeCluster = clusterAssignmentCurrent[i];
// ensure that exactly one thread works on each cluster
if (activeCluster % omp_num_threads() != omp_get_thread_num()) continue;
Делайте это только в том случае, если простое решение не дает достаточной производительности.
Другоецикл также прост
#pragma omp parallel for
for (int i = 0; i < numClusters; ++i) {
if (clusterMemberCount[i] != 0)
// for each coordinate
for (int j = 0; j < numCoords; ++j)
clustersCentroID[i*numCoords + j] /= clusterMemberCount[i];
}
Опять же, доступ к данным совершенно изолирован как с точки зрения корректности, так и, за исключением крайних случаев, ложного совместного использования.