从多个并行线程读取 STL 容器是安全的。然而,表现却很糟糕。为什么?
我创建了一个小对象,将一些数据存储在多重集中。这使得构造函数相当昂贵(在我的机器上大约为 5 usecs)。我将数十万个小对象存储在一个大型多重集中。处理这些对象是一项独立的业务,因此我将工作分配给多核计算机上运行的线程之间。每个线程从大型多重集中读取它需要的对象,并处理它们。
问题是从大多重集的读取不是并行进行的。看起来一个线程中的读取会阻塞另一线程中的读取。
下面的代码是我能做到的最简单的代码,并且仍然显示问题。首先,它创建一个包含 100,000 个小对象的大型多重集,每个小对象都包含自己的空多重集。然后它连续调用多重集复制构造函数两次,然后再次并行调用两次。
分析工具显示,串行复制构造函数大约需要 0.23 秒,而并行复制构造函数则需要两倍的时间。不知何故,并行副本相互干扰。
// a trivial class with a significant ctor and ability to populate an associative container
class cTest
{
multiset<int> mine;
int id;
public:
cTest( int i ) : id( i ) {}
bool operator<(const cTest& o) const { return id < o.id; }
};
// add 100,000 objects to multiset
void Populate( multiset<cTest>& m )
{
for( int k = 0; k < 100000; k++ )
{
m.insert(cTest(k));
}
}
// copy construct multiset, called from mainline
void Copy( const multiset<cTest>& m )
{
cRavenProfile profile("copy_main");
multiset<cTest> copy( m );
}
// copy construct multiset, called from thread
void Copy2( const multiset<cTest>& m )
{
cRavenProfile profile("copy_thread");
multiset<cTest> copy( m );
}
int _tmain(int argc, _TCHAR* argv[])
{
cRavenProfile profile("test");
profile.Start();
multiset<cTest> master;
Populate( master );
// two calls to copy ctor from mainline
Copy( master );
Copy( master );
// call copy ctor in parrallel
boost::thread* pt1 = new boost::thread( boost::bind( Copy2, master ));
boost::thread* pt2 = new boost::thread( boost::bind( Copy2, master ));
pt1->join();
pt2->join();
// display profiler results
cRavenProfile print_profile;
return 0;
}
这是输出
Scope Calls Mean (secs) Total
copy_thread 2 0.472498 0.944997
copy_main 2 0.233529 0.467058