2016-02-01 11 views
6

मैंने प्रश्न What's the performance penalty of weak_ptr? पढ़ा है लेकिन मेरे अपने परीक्षण अलग-अलग परिणाम दिखाते हैं।क्यों weak_ptr के माध्यम से कॉल करना इतना धीमा है?

मैं स्मार्ट पॉइंटर्स के साथ प्रतिनिधि बना रहा हूं। नीचे दिया गया सरल कोड weak_ptr के साथ प्रदर्शन समस्याओं को पुन: उत्पन्न करता है। क्या कोई मुझे बता सकता है क्यों?

#include <chrono> 
#include <functional> 
#include <iostream> 
#include <memory> 
#include <stdint.h> 
#include <string> 
#include <utility> 

struct Foo 
{ 
    Foo() : counter(0) { incrStep = 1;} 

    void bar() 
    { 
     counter += incrStep; 
    } 

    virtual ~Foo() 
    { 
     std::cout << "End " << counter << std::endl; 
    } 
private: 
    uint64_t counter; 
    uint64_t incrStep; 
}; 

void pf(const std::string &md, const std::function<void()> &g) 
{ 
    const auto st = std::chrono::high_resolution_clock::now(); 
    g(); 
    const auto ft = std::chrono::high_resolution_clock::now(); 
    const auto del = std::chrono::duration_cast<std::chrono::milliseconds>(ft - st); 
    std::cout << md << " \t: \t" << del.count() << std::endl; 
} 

और परीक्षण:

int main(int , char**) 
{ 
    volatile size_t l = 1000000000ULL; 
    size_t maxCounter = l; 

    auto a = std::make_shared<Foo>(); 
    std::weak_ptr<Foo> wp = a; 

    pf("call via raw ptr  ", [=](){ 
     for (size_t i = 0; i < maxCounter; ++i) 
     { 
      auto p = a.get(); 
      if (p) 
      { 
       p->bar(); 
      } 
     } 
    }); 

    pf("call via shared_ptr  ", [=](){ 
     for (size_t i = 0; i < maxCounter; ++i) 
     { 
      if (a) 
      { 
       a->bar(); 
      } 
     } 
    }); 

    pf("call via weak_ptr  ", [=](){ 
     std::shared_ptr<Foo> p; 
     for (size_t i = 0; i < maxCounter; ++i) 
     { 
      p = wp.lock(); 
      if (p) 
      { 
       p->bar(); 
      } 
     } 
    }); 

    pf("call via shared_ptr copy", [=](){ 
     volatile std::shared_ptr<Foo> p1 = a; 
     std::shared_ptr<Foo> p; 
     for (size_t i = 0; i < maxCounter; ++i) 
     { 
      p = const_cast<std::shared_ptr<Foo>& >(p1); 
      if (p) 
      { 
       p->bar(); 
      } 
     } 
    }); 

    pf("call via mem_fn   ", [=](){ 
     auto fff = std::mem_fn(&Foo::bar); 
     for (size_t i = 0; i < maxCounter; ++i) 
     { 
      fff(a.get()); 
     } 
    }); 

    return 0; 
} 

परिणाम:

$ ./test 
call via raw ptr   : 369 
call via shared_ptr   : 302 
call via weak_ptr   : 22663 
call via shared_ptr copy : 2171 
call via mem_fn    : 2124 
End 5000000000 

आप देख सकते हैं, weak_ptr बार नकल के साथ shared_ptr और std::mem_fn और 60 से 10 गुना धीमी कच्चे का उपयोग कर की तुलना में धीमी पीआरटी या shared_ptr.get()

+7

क्या आपने एक अनुकूलित निर्माण का परीक्षण किया था? – TartanLlama

+0

हां, मैं अपने परीक्षण – user2807083

+2

के निर्माण के लिए g ++ -O3 -std = C++ 11 का उपयोग कर रहा हूं एक 'weak_ptr' को' shared_ptr' के थ्रेड सुरक्षित अधिग्रहण को धीमा होने की आवश्यकता है। आपको केवल 'weak_ptr' का उपयोग करना चाहिए जब आप नहीं जानते कि साझा ऑब्जेक्ट नष्ट हो गया है या नहीं। अन्यथा * कच्चे सूचक * का उपयोग करें। – Galik

उत्तर

5

अपने परीक्षण को पुन: उत्पन्न करने की कोशिश में मुझे एहसास हुआ कि ऑप्टिमाइज़र इसे से अधिक को समाप्त कर सकता है। मैंने जो किया वह अधिक अनुकूलन को हराने के लिए यादृच्छिक संख्याओं का उपयोग करना था और ये परिणाम std::weak_ptrstd::shared_ptr या उसके कच्चे सूचक से धीमे तीन गुना होने के साथ यथार्थवादी प्रतीत होते हैं।

मैं प्रत्येक परीक्षा में चेकसम गणना सुनिश्चित करने के लिए वे सभी एक ही काम कर रहे हैं:

#include <chrono> 
#include <memory> 
#include <vector> 
#include <iomanip> 
#include <iostream> 

#define OUT(m) do{std::cout << m << '\n';}while(0) 

class Timer 
{ 
    using clk = std::chrono::steady_clock; 
    using microseconds = std::chrono::microseconds; 

    clk::time_point tsb; 
    clk::time_point tse; 

public: 

    void clear() { tsb = tse = clk::now(); } 
    void start() { tsb = clk::now(); } 
    void stop() { tse = clk::now(); } 

    friend std::ostream& operator<<(std::ostream& o, const Timer& timer) 
    { 
     return o << timer.secs(); 
    } 

    // return time difference in seconds 
    double secs() const 
    { 
     if(tse <= tsb) 
      return 0.0; 
     auto d = std::chrono::duration_cast<microseconds>(tse - tsb); 
     return d.count()/1000000.0; 
    } 
}; 

Timer timer; 

constexpr auto N = 100000000U; 

int main() 
{ 
    std::srand(std::time(0)); 

    std::vector<int> random_ints; 
    for(auto i = 0U; i < 1024; ++i) 
     random_ints.push_back(std::rand() % (i + 1)); 

    std::shared_ptr<int> sptr = std::make_shared<int>(std::rand() % 100); 
    int* rptr = sptr.get(); 
    std::weak_ptr<int> wptr = sptr; 

    unsigned sum = 0; 

    sum = 0; 
    timer.start(); 
    for(auto i = 0U; i < N; ++i) 
    { 
     sum += random_ints[i % random_ints.size()] * *sptr; 
    } 
    timer.stop(); 

    OUT("sptr: " << sum << " " << timer); 

    sum = 0; 
    timer.start(); 
    for(auto i = 0U; i < N; ++i) 
    { 
     sum += random_ints[i % random_ints.size()] * *rptr; 
    } 
    timer.stop(); 

    OUT("rptr: " << sum << " " << timer); 

    sum = 0; 
    timer.start(); 
    for(auto i = 0U; i < N; ++i) 
    { 
     sum += random_ints[i % random_ints.size()] * *wptr.lock(); 
    } 
    timer.stop(); 

    OUT("wptr: " << sum << " " << timer); 
} 

संकलक झंडे:

g++ -std=c++14 -O3 -g0 -D NDEBUG -o bin/timecpp src/timecpp.cpp 

उदाहरण आउटपुट:

sptr: 3318793206 1.30389 // shared pointer 
rptr: 3318793206 1.2751 // raw pointer 
wptr: 3318793206 3.13879 // weak pointer 
+0

यह सवाल का जवाब नहीं देता है। प्रश्न, जैसा कि मैंने इसे पढ़ा है, "क्या कमजोर_पीआर धीमा बनाता है?" नहीं "क्यों [कुछ कोड] दिखाता है कि weak_ptr धीमा है?" –

+1

@MatthewJamesBriggs जिस तरह से मैंने सवाल पढ़ा है, "यह मेरे विशिष्ट परीक्षणों में धीमा क्यों है", क्योंकि वह एक ऐसे प्रश्न से जुड़ा हुआ है जो पहले से ही बताता है कि यह धीमा क्यों है। लेकिन ओपी आश्चर्यचकित है कि ** उनके ** परीक्षण * धीमे * प्रदर्शन प्रदान कर रहे हैं। और वह जानना चाहता है क्यों। शीर्षक यह है कि "weak_ptr के माध्यम से क्यों कॉल करना ** ** ** धीमा है?" (** ** पर जोर) – Galik

+0

ओह, मैं देखता हूं, यह किसी भी तरह से स्पष्ट रूप से नहीं बताया गया है। –

संबंधित मुद्दे