[英]What's the performance penalty of weak_ptr?
我目前正在為游戲設計一個對象結構,在我的案例中,最自然的組織變成了一棵樹。 作為智能指針的忠實粉絲,我只使用shared_ptr
。 但是,在這種情況下,樹中的子節點將需要訪問它的父節點(例如——地圖上的生物需要能夠訪問地圖數據——因此他們的父節點的數據。
擁有的方向當然是地圖擁有它的存在,因此擁有指向它們的共享指針。 然而,要從存在中訪問地圖數據,我們需要一個指向父級的指針——智能指針的方式是使用引用,即weak_ptr
。
然而,我曾經讀到鎖定weak_ptr
是一項昂貴的操作——也許這不再是真的——但考慮到weak_ptr
會經常被鎖定,我擔心這種設計注定會導致性能不佳。
因此問題是:
鎖定weak_ptr 的性能損失是什么? 它有多重要?
來自 Boost 1.42 源代碼( <boost/shared_ptr/weak_ptr.hpp>
第 155 行):
shared_ptr<T> lock() const // never throws
{
return shared_ptr<element_type>( *this, boost::detail::sp_nothrow_tag() );
}
因此,James McNellis 的評論是正確的; 這是復制構造shared_ptr
的成本。
對於我自己的項目,我能夠通過在任何 boost 包含之前添加#define BOOST_DISABLE_THREADS
來顯着提高性能。 這避免了 weak_ptr::lock 的自旋鎖/互斥開銷,這在我的項目中是一個主要瓶頸。 由於該項目不是多線程 wrt boost,我可以做到這一點。
使用/取消引用shared_ptr幾乎就像訪問原始 ptr,與常規指針訪問相比,鎖定weak_ptr是一種性能“重”操作,因為此代碼必須“線程感知”才能正常工作,以防萬一另一個線程觸發釋放指針引用的對象。 至少,它必須執行某種互鎖/原子操作,根據定義,這種操作比常規內存訪問慢得多。
像往常一樣,查看發生了什么的一種方法是檢查生成的代碼:
#include <memory>
class Test
{
public:
void test();
};
void callFuncShared(std::shared_ptr<Test>& ptr)
{
if (ptr)
ptr->test();
}
void callFuncWeak(std::weak_ptr<Test>& ptr)
{
if (auto p = ptr.lock())
p->test();
}
void callFuncRaw(Test* ptr)
{
if (ptr)
ptr->test();
}
通過 shared_ptr 和原始指針訪問是一樣的。 由於shared_ptr
是作為引用傳遞的,我們需要加載引用的值,這就是為什么shared_ptr版本的區別只是一個額外的加載。
callFuncShared:
callFuncWeak:
通過weak_ptr
調用會產生10 倍的代碼,並且它最多必須通過鎖定的比較交換,這本身將比取消引用raw 或shared_ptr 花費10 倍以上的CPU 時間:
只有當共享計數器不為零時,它才能加載指向實際對象的指針並使用它(通過調用對象,或創建shared_ptr
)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.