2012-03-02 14 views
6

मैं एक प्रगति बार वर्ग है कि एक std::ostream लिए एक अद्यतन प्रगति बार हर n टिक आउटपुट लिख रहा हूँ:का आकलन समय में छोड़ दिया सी ++ 11

class progress_bar 
{ 
public: 
    progress_bar(uint64_t ticks) 
    : _total_ticks(ticks), ticks_occured(0), 
     _begin(std::chrono::steady_clock::now()) 
    ... 
    void tick() 
    { 
    // test to see if enough progress has elapsed 
    // to warrant updating the progress bar 
    // that way we aren't wasting resources printing 
    // something that hasn't changed 
    if (/* should we update */) 
    { 
     ... 
    } 
    } 
private: 
    std::uint64_t _total_ticks; 
    std::uint64_t _ticks_occurred; 
    std::chrono::steady_clock::time_point _begin; 
    ... 
} 

मैं भी उत्पादन समय शेष करना चाहते हैं।

time_left = (time_taken/_total_ticks) * (_total_ticks - _ticks_occured)

भागों मैं अपने वर्ग के लिए भरने के लिए चाहते हैं time_left और time_taken, सी का उपयोग कर रहे हैं: मैं another question समय शेष है (चर नाम मेरी कक्षा फिट करने के लिए बदल दिया है) कहा गया है कि पर एक सूत्र पाया ++ 11 का नया <chrono> शीर्षलेख।

मुझे पता है कि मुझे std::chrono::steady_clock का उपयोग करने की आवश्यकता है, लेकिन मुझे यकीन नहीं है कि इसे कोड में कैसे एकीकृत किया जाए। मुझे लगता है कि समय मापने का सबसे अच्छा तरीका std::uint64_t नैनोसेकंड के रूप में होगा।

मेरे प्रश्न हैं:

  1. वहाँ <chrono> में एक समारोह है कि एक std::string में नैनोसेकंड में परिवर्तित कर देंगे है, "3m12s" कुछ ऐसा कहना?
  2. क्या मुझे std::chrono::steady_clock::now() का उपयोग हर बार जब मैं अपनी प्रगति पट्टी को अपडेट करता हूं, और निर्धारित करने के लिए _begin से घटा देना चाहिए?
  3. यह तय करने के लिए एक बेहतर एल्गोरिथ्म time_left

उत्तर

7

क्या इसमें कोई फ़ंक्शन नैनोसेकंड को में एक std :: स्ट्रिंग में परिवर्तित करेगा, "3m12s" जैसा कुछ कहें?

सं।लेकिन मैं आपको दिखाऊंगा कि आप इसे आसानी से कैसे कर सकते हैं।

मैं std :: chrono :: steady_clock :: उपयोग करना चाहिए अब() हर बार मैं मेरी प्रगति बार अपडेट करते हैं और घटाना है कि TIME_LEFT निर्धारित करने के लिए _begin से?

हां।

वहाँ TIME_LEFT

निर्धारित करने के लिए एक बेहतर एल्गोरिथ्म है हां। निचे देखो।

संपादित

मैं मूल रूप से "के रूप में टिक" की गलत व्याख्या की थी "घड़ी टिक्स", वास्तविकता में जब "टिक्स" काम की इकाइयां हैं और _ticks_occurred/_total_ticks% job_done रूप में व्याख्या की जा सकती है। तो मैंने तदनुसार प्रस्तावित progress_bar बदल दिया है।

मेरा मानना ​​है कि समीकरण:

time_left = (time_taken/_total_ticks) * (_total_ticks - _ticks_occured) 

सही नहीं है। यह एक सैनिटी चेक पास नहीं करता है: यदि _ticks_occured == 1 और _total_ticks बड़ा है, तो time_left लगभग बराबर (ठीक है, थोड़ा कम) time_taken। यह समझ में नहीं आता है।

मैं उपरोक्त समीकरण को फिर से लिखने रहा हो:

time_left = time_taken * (1/percent_done - 1) 

जहां

percent_done = _ticks_occurred/_total_ticks 

अब percent_done के रूप में शून्य दृष्टिकोण, time_left अनंत दृष्टिकोण है, और जब percent_done दृष्टिकोण 1, 'time_left दृष्टिकोण 0. जब percent_done 10% है, time_left9*time_taken है। यह मेरी अपेक्षाओं को पूरा करता है, प्रति कार्य-टिक के लिए मोटे तौर पर रैखिक समय लागत को मानता है।

class progress_bar 
{ 
public: 
    progress_bar(uint64_t ticks) 
    : _total_ticks(ticks), _ticks_occurred(0), 
     _begin(std::chrono::steady_clock::now()) 
// ... 
    {} 
    void tick() 
    { 
    using namespace std::chrono; 
    // test to see if enough progress has elapsed 
    // to warrant updating the progress bar 
    // that way we aren't wasting resources printing 
    // something that hasn't changed 
    if (/* should we update */) 
    { 
     // somehow _ticks_occurred is updated here and is not zero 
     duration time_taken = Clock::now() - _begin; 
     float percent_done = (float)_ticks_occurred/_total_ticks; 
     duration time_left = time_taken * static_cast<rep>(1/percent_done - 1); 
     minutes minutes_left = duration_cast<minutes>(time_left); 
     seconds seconds_left = duration_cast<seconds>(time_left - minutes_left); 
    } 
    } 
private: 
    typedef std::chrono::steady_clock Clock; 
    typedef Clock::time_point time_point; 
    typedef Clock::duration duration; 
    typedef Clock::rep rep; 
    std::uint64_t _total_ticks; 
    std::uint64_t _ticks_occurred; 
    time_point _begin; 
    //... 
}; 

std :: chrono :: यातायात में ट्रैफिक :: जब भी आप कर सकते हैं। इस तरह <chrono> आपके लिए सभी रूपांतरण करता है। टाइपपीफ लंबे नामों के साथ टाइपिंग को कम कर सकते हैं। और समय और सेकंड में समय को तोड़ना उतना ही आसान है जितना ऊपर दिखाया गया है।

अपने उत्तर में bames53 नोट्स के रूप में, यदि आप मेरी <chrono_io> सुविधा का उपयोग करना चाहते हैं, तो यह भी अच्छा है। आपकी ज़रूरतें इतनी सरल हो सकती हैं कि आप नहीं चाहते हैं। यह एक निर्णय कॉल है। bames53 का जवाब एक अच्छा जवाब है। मैंने सोचा कि ये अतिरिक्त विवरण भी उपयोगी हो सकते हैं।

संपादित

मैंने गलती से ऊपर कोड में एक बग छोड़ दिया है। और उपर्युक्त कोड को पैच करने के बजाय, मैंने सोचा कि यह बग को इंगित करना और यह दिखाने के लिए <chrono> का उपयोग करना एक अच्छा विचार होगा।

बग यहाँ है:

duration time_left = time_taken * static_cast<rep>(1/percent_done - 1); 

और यहाँ:

typedef Clock::duration duration; 

अभ्यास steady_clock::duration में आमतौर पर एक अभिन्न प्रकार के आधार पर किया जाता है। <chrono> इसे rep (प्रतिनिधित्व के लिए संक्षिप्त) कहते हैं। और जब percent_done 50% से अधिक है, तो time_taken द्वारा गुणा किया जाने वाला कारक 1 से कम होने वाला है। और rep अभिन्न है, जो 0 तक कास्ट हो जाता है। इसलिए यह progress_bar केवल पहले 50% के दौरान अच्छा व्यवहार करता है और भविष्यवाणी करता है 0 बार पिछले 50% के दौरान छोड़ दिया।

इसे ठीक करने की कुंजी duration एस में यातायात के लिए है जो पूर्णांक के बजाय फ़्लोटिंग पॉइंट पर आधारित है। और <chrono> ऐसा करना बहुत आसान बनाता है।

typedef std::chrono::steady_clock Clock; 
typedef Clock::time_point time_point; 
typedef Clock::period period; 
typedef std::chrono::duration<float, period> duration; 

duration अब steady_clock::duration रूप में एक ही टिक अवधि है लेकिन प्रतिनिधित्व के लिए एक float उपयोग करता है।

duration time_left = time_taken * (1/percent_done - 1); 

यहाँ पूरे पैकेज है फिर से इन सुधारों के साथ: और अब time_left के लिए गणना बंद static_cast छोड़ सकते हैं एक छोटे से परीक्षण की तरह

class progress_bar 
{ 
public: 
    progress_bar(uint64_t ticks) 
    : _total_ticks(ticks), _ticks_occurred(0), 
     _begin(std::chrono::steady_clock::now()) 
// ... 
    {} 
    void tick() 
    { 
    using namespace std::chrono; 
    // test to see if enough progress has elapsed 
    // to warrant updating the progress bar 
    // that way we aren't wasting resources printing 
    // something that hasn't changed 
    if (/* should we update */) 
    { 
     // somehow _ticks_occurred is updated here and is not zero 
     duration time_taken = Clock::now() - _begin; 
     float percent_done = (float)_ticks_occurred/_total_ticks; 
     duration time_left = time_taken * (1/percent_done - 1); 
     minutes minutes_left = duration_cast<minutes>(time_left); 
     seconds seconds_left = duration_cast<seconds>(time_left - minutes_left); 
     std::cout << minutes_left.count() << "m " << seconds_left.count() << "s\n"; 
    } 
    } 
private: 
    typedef std::chrono::steady_clock Clock; 
    typedef Clock::time_point time_point; 
    typedef Clock::period period; 
    typedef std::chrono::duration<float, period> duration; 
    std::uint64_t _total_ticks; 
    std::uint64_t _ticks_occurred; 
    time_point _begin; 
    //... 
}; 

कुछ भी नहीं है ... ;-)

+0

"टिक" का कारण प्रगति का प्रतिनिधित्व करना है, यानी: मेरे पास पूरा करने के लिए 1,000,000 ऑपरेशन (टिक) हैं। जो मैं बता सकता हूं उससे बूस्ट में 'chrono_io' है। क्या आप इसका उपयोग करने की सलाह देंगे? – nerozehl

+1

ओह, "टिक" काम की एक इकाई का प्रतिनिधित्व करता है, समय की इकाई नहीं? यदि हां, तो मैंने आपके प्रश्न को गलत समझा। मैंने गलती से "घड़ी टिक" पढ़ा। बूस्ट '' '' की एक अधिकृत प्रति है। यदि आपको यह उपयोगी लगता है तो इसका उपयोग करना ठीक होना चाहिए। मैं भविष्य के मानक के लिए '' प्रस्तावित कर रहा हूं, इसलिए इस पर प्रतिक्रिया रखना अच्छा होगा। –

+0

हां काम की एक इकाई होने पर टिकटें .. मुझे लगता है कि मुझे और स्पष्ट होना चाहिए था, मुझे उस पर परेशानी के लिए खेद है। आपका बहुत बहुत धन्यवाद! :) – nerozehl

3

chrono पुस्तकालय अवधियों का प्रतिनिधित्व करने के लिए प्रकार शामिल है। आपको इसे कुछ 'ज्ञात' इकाई के एक फ्लैट पूर्णांक में परिवर्तित नहीं करना चाहिए। जब आप एक ज्ञात इकाई चाहते हैं तो केवल chrono प्रकारों का उपयोग करें, उदा। 'std :: chrono :: nanoseconds', और duration_cast। या फ़्लोटिंग पॉइंट प्रस्तुति और एसआई अनुपात में से एक का उपयोग करके अपना खुद का अवधि प्रकार बनाएं। जैसे std::chrono::duration<double,std::nano>। संकलन समय पर duration_cast या फ़्लोटिंग पॉइंट अवधि राउंडिंग के बिना प्रतिबंधित है।

क्रोनो के लिए आईओ सुविधाओं ने इसे सी ++ 11 में नहीं बनाया है, लेकिन आप here से स्रोत प्राप्त कर सकते हैं। इसका उपयोग करके आप केवल अवधि के प्रकार को अनदेखा कर सकते हैं, और यह सही इकाइयों को प्रिंट करेगा। मुझे नहीं लगता कि वहां कुछ भी है जो मिनट, सेकंड इत्यादि में समय दिखाएगा, लेकिन ऐसी चीज लिखना बहुत कठिन नहीं होना चाहिए।

मुझे नहीं पता कि steady_clock::now() पर कॉल करने के बारे में चिंतित होने के बहुत अधिक कारण हैं, यदि यह आपकी पूछताछ है। मैं उम्मीद करता हूं कि ज्यादातर प्लेटफॉर्मों को उस तरह की चीज़ के लिए एक बहुत तेज़ टाइमर होना चाहिए। हालांकि यह कार्यान्वयन पर निर्भर करता है। स्पष्ट रूप से यह आपके लिए कोई समस्या पैदा कर रहा है, इसलिए शायद आप steady_clock::now() को if (/* should we update */) ब्लॉक के अंदर कॉल कर सकते हैं, जिसे कॉल आवृत्ति पर उचित सीमा डालना चाहिए।

स्पष्ट रूप से शेष समय का अनुमान लगाने के अन्य तरीके हैं। उदाहरण के लिए अब तक प्रगति पर औसत लेने की बजाय (जो सूत्र आप दिखाते हैं), आप अंतिम एन टिकों से औसत ले सकते हैं। या दोनों अनुमान लगाएं और दो अनुमानों का भारित औसत लें।

+0

चाहेंगे आप std :: chrono पर boost :: chrono का उपयोग करने की सलाह देते हैं? – nerozehl

+0

बूस्ट :: क्रोनो में अतिरिक्त आईओ सुविधाएं हैं, और विंडोज़ पर इसका संकल्प वीएस 11 बीटा में पुस्तकालयों से बेहतर है। लेकिन साथ ही जब भी संभव हो मैं मानक का उपयोग करना पसंद करता हूं। मुझे किसी भी तरह का मुद्दा नहीं दिख रहा है। – bames53

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