我想知道如何在保持性能的同时使用线程安全的命令模式。我进行了一个模拟,我执行了数百亿次的迭代;性能是至关重要的。
在这个模拟中,我有一堆Moves,它们在我的模拟中对对象执行命令。基类如下所示:
class Move
{
public:
virtual ~Move(){}
// Perform a move.
virtual void Perform(Object& obj) = 0;
// Undo a move.
virtual void Undo() = 0;
};我在Perform上传递对象而不是构造函数的原因(就像命令模式中的典型情况一样)是因为我不能在每次迭代时实例化一个新的Move对象。相反,Move的具体实现只需使用Object,维护指向它的指针,并在需要时保持以前的状态。下面是一个具体实现的示例:
class ConcreteMove : public Move
{
std::string _ns;
std::string _prev;
Object* _obj;
ConcreteMove(std::string newstring): _ns(newstring) {}
virtual void Perform(Object& obj) override
{
_obj= &obj;
_prev = obj.GetIdentifier();
obj.SetIdentifier(_ns);
}
virtual void Undo()
{
_obj->SetIdentifier(_prev);
}
};不幸的是,我为此付出的代价是线程安全。我想并行化我的循环,其中多个迭代器同时执行对一组对象的移动。但是很明显,ConcreteMove的一个实例不能被重用,因为我是如何实现它的。
我考虑让Perform返回一个可以传递给Undo的State对象,这样可以使实现线程安全,因为它独立于ConcereteMove状态。然而,在每次迭代中创建和销毁这样一个对象的代价太高了。
此外,该仿真具有一个Moves向量,因为每次迭代都可以执行存储在一个MoveManager类中的多个动作,该类包含一个由客户端实例化的Move对象指针向量。我以这种方式设置它,因为每个特定具体移动的构造函数都使用参数(参见上面的示例)。
我考虑为Move和MoveManager编写一个复制操作符,这样就可以在线程之间复制它,但是我不认为这是一个正确的答案,因为这样Move对象的所有权就落在MoveManager而不是客户端(客户机只负责第一个实例)上。同样,MoveManager和维护它的责任也是如此。
MoveManager更新:这是我的(如果它重要的话)
class MoveManager
{
private:
std::vector<Move*> _moves;
public:
void PushMove(Move& move)
{
_moves.push_back(&move);
}
void PopMove()
{
_moves.pop_back();
}
// Select a move by index.
Move* SelectMove(int i)
{
return _moves[i];
}
// Get the number of moves.
int GetMoveCount()
{
return (int)_moves.size();
}
};Move澄清:我所需要的只是每个线程一个对象的集合。每次迭代都会重用它们,每次都在不同对象上调用。。
有人知道如何以线程安全的方式有效地解决这个问题吗?
谢谢!
发布于 2015-03-23 15:53:00
那么线程ID的概念呢?同样,为什么不预先构造标识符字符串并将指针传递给它们呢?
class ConcreteMove : public Move
{
std::string *_ns;
std::vector<std::string *> _prev;
std::vector<Object *> _obj;
ConcreteMove(unsigned numthreads, std::string *newstring)
: _ns(newstring),
_prev(numthreads),
_obj(numthreads)
{
}
virtual void Perform(unsigned threadid, Object &obj) override
{
_obj[threadid] = &obj;
_prev[threadid] = obj.GetIdentifier();
obj.SetIdentifier(_ns);
}
virtual void Undo(unsigned threadid)
{
_obj[threadid]->SetIdentifier(_prev[threadid]);
}
};发布于 2015-03-16 23:52:49
有明确的要求是不可能的。具体来说,
您想要存储数据,而不需要在任何地方存储数据。因此,没有答案。然而,如果你愿意改变你的需求,毫无疑问有很多方法来解决你的问题(不管它是什么-我从描述中看不出来)。
我也无法估计你一次需要多少移动对象。如果这个数字相当低,那么一个专门的分配方案可能会解决你的部分问题。同样,如果大多数移动对象都是重复的,那么不同的专门分配方案可能会有所帮助。
一般来说,你想要的东西是无法解决的,但是放松需求,这应该不难。
发布于 2015-03-23 20:43:50
移动管理器不应该包含指针向量,它应该是移动对象的向量
std::vector<Move> _moves;似乎每个线程都有一个移动管理器,所以不会出现多线程问题,将向量容量设置为最大,然后将执行操作和其他操作应用到向量无新分配中,然后重用移动对象。
https://stackoverflow.com/questions/29055249
复制相似问题