Я попытался распараллелить цикл for некоторого последовательного кода C ++ с openmp.Сложность заключается в правильной обработке
linkingVarVals
. Чтобы получить те же результаты, что и в последовательном коде, я использовал упорядоченное предложение openmp.Следующий подход, кажется, работает в моем случае.Но, к сожалению, код openmp на самом деле медленнее, чем последовательное выполнение.Предположительно это вызвано упорядоченной оговоркой.Есть ли способ в моем случае ускорить реализацию openmp?
typedef tuple<int,int,int> key3;
struct key3_hash : public std::unary_function<key3, std::size_t> {
std::size_t operator()(const key3& k) const {
return std::get<0>(k) ^ std::get<1>(k) ^ std::get<2>(k);
}
};
struct key3_equal : public std::binary_function<key3, key3, bool> {
bool operator()(const key3& v0, const key3& v1) const {
return (std::get<0>(v0) == std::get<0>(v1) &&
std::get<1>(v0) == std::get<1>(v1) &&
std::get<2>(v0) == std::get<2>(v1));
}
};
typedef tuple<int,int> key2;
struct key2_hash : public std::unary_function<key2, std::size_t> {
std::size_t operator()(const key2& k) const {
return std::get<0>(k) ^ std::get<1>(k);
}
};
struct key2_equal : public std::binary_function<key2, key2, bool> {
bool operator()(const key2& v0, const key2& v1) const {
return (std::get<0>(v0) == std::get<0>(v1) &&
std::get<1>(v0) == std::get<1>(v1));
}
};
typedef unordered_map<key3, double, key3_hash, key3_equal> CoeffMap;
typedef unordered_map<key3, GRBVar, key3_hash, key3_equal> VarMap;
typedef unordered_map<key2, double, key2_hash, key2_equal> ValueMap;
typedef unordered_map<key3, GRBConstr, key3_hash, key3_equal> ConstrMap;
void myalgorithm(GRBModel model,
const vector<GRBModel*>& submips,
const set<string>& linkingvarnames,
const map<string,int>& nametoidxmap,
const map<int,string>& idxtonamemap,
const map<int,set<int> >& linkvaridxtoblock,
const map<int,set<int> >& blocktolinkvaridx)
{
size_t nBlocks = submips.size();
size_t nVars = model.get(GRB_IntAttr_NumVars);
CoeffMap slackPosCoeffs;
CoeffMap slackNegCoeffs;
VarMap slackPosVars;
VarMap slackNegVars;
ValueMap linkingVarVals;
ConstrMap couplingCons;
// the following code shows the connection between
// submips[block] and couplingCons
for (size_t block = 0; block < nBlocks; ++block) {
set<int> linkVarsInBlock = blocktolinkvaridx.at(block);
for (set<int>::const_iterator it = linkVarsInBlock.begin(), ei = linkVarsInBlock.end(); it != ei; ++it) {
int linkVarIdx = *it;
set<int> blocksContainingLinkVar = linkvaridxtoblock.at(linkVarIdx);
for (set<int>::const_iterator jt = blocksContainingLinkVar.begin(), ej = blocksContainingLinkVar.end(); jt != ej; ++jt) {
int blockContainingLinkVar = *jt;
if (blockContainingLinkVar != block) {
auto idx2 = make_tuple(blockContainingLinkVar, linkVarIdx);
auto idx3 = make_tuple(block, blockContainingLinkVar, linkVarIdx);
stringstream constrName;
constrName << idxtonamemap.at(linkVarIdx) << "_Coupling_Block_" << blockContainingLinkVar;
couplingCons[idx3] = submips[block]->addConstr(submips[block]->getVarByName(idxtonamemap.at(linkVarIdx)) + slackPosVars.at(idx3) - slackNegVars.at(idx3) == linkingVarVals.at(idx2), constrName.str());
}
}
}
submips[block]->update();
}
#if defined(_OPENMP)
// set number of openmp threads
unsigned int numprocs = omp_get_num_procs();
cout << "=== NumProcessors " << numprocs << endl;
unsigned int numthreads = numprocs > 1 ? numprocs :
std::min((int)nBlocks, 4);
omp_set_num_threads(numthreads);
cout << "=== OpenMP threads " << numthreads << endl;
#endif
double newRHS;
#pragma omp parallel for ordered schedule(dynamic)
// 1. loop
for (size_t block = 0; block < nBlocks; ++block) {
set<int> linkVarsInBlock = blocktolinkvaridx.at(block);
// 2. loop
for (set<int>::const_iterator it = linkVarsInBlock.begin(), ei = linkVarsInBlock.end(); it != ei; ++it) {
int linkVarIdx = *it;
set<int> blocksContainingLinkVar = linkvaridxtoblock.at(linkVarIdx);
// 3. loop
for (set<int>::const_iterator jt = blocksContainingLinkVar.begin(), ej = blocksContainingLinkVar.end(); jt != ej; ++jt) {
int blockContainingLinkVar = *jt;
if (blockContainingLinkVar != block) {
auto idx3 = make_tuple(block, blockContainingLinkVar, linkVarIdx);
auto idx2 = make_tuple(blockContainingLinkVar, linkVarIdx);
GRBConstr c = couplingCons.at(idx3);
string name = c.get(GRB_StringAttr_ConstrName);
double oldRHS = c.get(GRB_DoubleAttr_RHS);
#pragma omp ordered
{
newRHS = linkingVarVals.at(idx2);
}
c.set(GRB_DoubleAttr_RHS, newRHS);
slackPosVars.at(idx3).set(GRB_DoubleAttr_Obj, slackPosCoeffs.at(idx3));
slackNegVars.at(idx3).set(GRB_DoubleAttr_Obj, slackNegCoeffs.at(idx3));
}
}
}
submips[block]->optimize();
// 4. loop
for (set<int>::const_iterator it = linkVarsInBlock.begin(), ei = linkVarsInBlock.end(); it != ei; ++it) {
int linkVarIdx = *it;
auto idx2 = make_tuple(block, linkVarIdx);
linkingVarVals[idx2] = submips[block]->getVarByName(idxtonamemap.at(linkVarIdx)).get(GRB_DoubleAttr_X);
}
}
}