2009-03-05 11 views
7

मुझे अपेक्षाकृत महंगा डेटा-फ़ेचिंग ऑपरेशन मिला है जिसके परिणामस्वरूप मैं कैश करना चाहता हूं। इस आपरेशन const तरीकों से कहा जाता है, मोटे तौर पर इस तरह:सी ++ में महंगे डेटा कैशिंग - फ़ंक्शन-स्कोप्ड स्टेटिक्स बनाम परिवर्तनीय सदस्य चर

double AdjustData(double d, int key) const { 
    double factor = LongRunningOperationToFetchFactor(key); 
    return factor * d; 
} 

मैं AdjustData चाहते हैं const रहने के लिए है, लेकिन मैं तो मैं केवल यह पहली बार लाने कारक बाहर कैश करने के लिए चाहते हैं। वर्तमान में मैं परिणाम संग्रहीत करने के लिए mutable map<int, double> का उपयोग कर रहा हूं (नक्शा key से factor तक), लेकिन मैं सोच रहा हूं कि फ़ंक्शन-स्कोप्ड स्थिर का उपयोग करना बेहतर समाधान हो सकता है - यह कारक केवल इस फ़ंक्शन द्वारा आवश्यक है, और है कक्षा के बाकी हिस्सों के लिए अप्रासंगिक।

क्या यह जाने का एक अच्छा तरीका प्रतीत होता है? क्या कोई बेहतर विकल्प हैं? विशेष रूप से थ्रेड-सुरक्षा के संबंध में, मैं किस चीज के बारे में सोच सकता हूं।

धन्यवाद,

Dom

उत्तर

5

मैं इस तरह से कुछ के साथ LongRunningOperationToFetchFactor के कार्यान्वयन को लपेटूंगा। मैं बूस्ट स्कोप्ड लॉक का उपयोग कर रहा हूं लेकिन आप अन्य लॉकिंग फ्रेमवर्क के साथ ऐसा कुछ कर सकते हैं।

#include <boost/thread/thread.hpp> 
#include <boost/thread/mutex.hpp> 
#include <map> 

using namespace std; 

static boost::mutex myMutex; 
static map<int,double> results; 

double CachedLongRunningOperationToFetchFactor(int key) 
{ 

    { 
     boost::mutex::scoped_lock lock(myMutex); 

     map<int,double>::iterator iter = results.find(key); 
     if (iter != results.end()) 
     { 
      return (*iter).second; 
     } 
    } 
    // not in the Cache calculate it 
    result = LongRunningOperationToFetchFactor(key); 
    { 
     // we need to lock the map again 
     boost::mutex::scoped_lock lock(myMutex); 
     // it could be that another thread already calculated the result but 
     // map assignment does not care. 
     results[key] = result; 
    } 
    return result; 
} 

यदि यह वास्तव में एक लंबे समय तक चलने वाला ऑपरेशन है तो म्यूटेक्स को लॉक करने की लागत न्यूनतम होनी चाहिए।

यह आपके प्रश्न से बिल्कुल स्पष्ट नहीं था, लेकिन यदि फ़ंक्शन LongRunningOperationToFetchFactor आपके वर्ग का सदस्य कार्य है तो आप चाहते हैं कि नक्शा उसी कक्षा में उत्परिवर्तनीय मानचित्र हो। मैं पहुंच के लिए एकल स्थैतिक म्यूटेक्स अभी भी पर्याप्त तेज़ है।

+0

लंबे समय तक चलने वाले ऑपरेशन को लॉक करना आवश्यक नहीं है, बस मानचित्र पर कॉल ढूंढें/डालें। –

+0

मुझे लगता है कि आप सही हैं। मुझे इसे आगे ट्यून करने दें। –

+0

ताला पकड़ने के दौरान स्थैतिक मानचित्र बनाना थ्रेड-सुरक्षित होने की गारंटी नहीं है, क्योंकि यदि आप दो थ्रेड इस फ़ंक्शन को पहली बार उपयोग करते हैं तो नक्शा को दोबारा बना सकते हैं और दोबारा नष्ट कर सकते हैं। Http://blogs.msdn.com/oldnewthing/archive/2004/03/08/85901.aspx – bk1e

0

जब तक मुझे समझ नहीं आता, यह मेरे लिए स्पष्ट है कि आप इस एक स्थिर बनाना चाहते लगता है:

double AdjustData(double d) const { 
    static const double kAdjustFactor = LongRunningOperationToFetchFactor(); 
    return kAdjustFactor * d; 
} 

इस तरह आप केवल कारक लाने एक बार।

+0

हाय लिंडसे - धन्यवाद, यही वह था जो मैं सोच रहा था। मैंने वास्तविक समस्या को दूर करने के लिए मेरे प्रश्न को थोड़ा सा संपादित किया है। मैं इस मामले में स्थिर स्थिरांक का उपयोग नहीं कर सकता, इसलिए मुझे लगता है कि मैं एक स्थिर मानचित्र का उपयोग करता हूं और नक्शा प्रविष्टियों के आसपास किसी प्रकार का लॉकिंग करता हूं। क्या यह सही लगता है? –

+0

आप किस बारे में बात कर रहे हैं काम करेंगे, लेकिन समाधान में कुछ हद तक * खराब * गंध है :) (रिफैक्टरिंग पुस्तक से लिया गया)। क्या यह ऐसा कुछ है जिसे उपयोगकर्ता कई अलग-अलग 'कुंजी' के लिए शुरू करता है जिसे आप अलग थ्रेड पर चला सकते हैं और परिणाम पूरा होने पर परिणाम प्रदर्शित कर सकते हैं? –

+0

यदि आप इसे स्थिर बनाते हैं, तो कक्षा की सभी वस्तुएं मूल्य साझा करेंगी। क्या ये वही है जो तुम चाहते हो? –

1

आप singleton pattern (1) का उपयोग ऐसे वर्ग के साथ कर सकते हैं जो लंबे समय तक चलने वाले ऑपरेशन को निष्पादित करता है और परिणाम कैश करता है। इस उदाहरण का उपयोग अन्य वर्गों के कॉन्स सदस्य कार्यों में किया जा सकता है। थ्रेड सुरक्षा के लिए मानचित्र डेटा संरचना से आवेषण और निष्कर्षणों की रक्षा के लिए पारस्परिक बहिष्कार पर विचार करें। यदि बहु-थ्रेडेड प्रदर्शन एक बड़ा मुद्दा है, तो आप एक साथ एक ही कुंजी की गणना करने से कई धागे को रोकने के लिए प्रगति के रूप में फ्लैग कुंजी को ध्वजांकित कर सकते हैं।

#include <cstdlib> 
#include <iostream> 
#include <map> 

using namespace std; 

class FactorMaker { 
    map<int, double> cache; 

    double longRunningFetch(int key) 
    { 
     const double factor = static_cast<double> (rand())/RAND_MAX; 
     cout << "calculating factor for key " << key << endl; 
     // lock 
     cache.insert(make_pair(key, factor)); 
     // unlock 
     return factor; 
    } 

public: 
    double getFactor(int key) { 
     // lock 
     map<int, double>::iterator it = cache.find(key); 
     // unlock 
     return (cache.end() == it) ? longRunningFetch(key) : it->second; 
    } 
}; 

FactorMaker & getFactorMaker() 
{ 
    static FactorMaker instance; 
    return instance; 
} 

class UsesFactors { 
public: 
    UsesFactors() {} 

    void printFactor(int key) const 
    { 
     cout << getFactorMaker().getFactor(key) << endl; 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    const UsesFactors obj; 

    for (int i = 0; i < 10; ++i) 
     obj.printFactor(i); 

    for (int i = 0; i < 10; ++i) 
     obj.printFactor(i); 

    return EXIT_SUCCESS; 
} 

(1) सिंगलटन पैटर्न निहायत याद किया जा सकता है। तो, अगर आप इसे पहली बार देख रहे हैं तो कृपया इसके साथ पागल होने से बचें।

3

मैं इस कैश को स्थानीय स्थिर बना दूंगा। परिवर्तनीय मानचित्र कैशिंग परिणामों के लिए समाधान है। अन्यथा यह आपके कार्य को बेकार कर देगा, क्योंकि आपकी कक्षा की विभिन्न वस्तुएं एक ही कैश साझा करेंगी, क्योंकि स्थानीय स्थिर कैश सभी ऑब्जेक्ट्स के लिए समान है। यदि परिणाम ऑब्जेक्ट पर निर्भर नहीं है तो आप स्थानीय स्थैतिक का उपयोग कर सकते हैं। लेकिन फिर मैं खुद से पूछूंगा कि फ़ंक्शन आपके ऑब्जेक्ट का गैर-स्थैतिक सदस्य क्यों है, अगर उसे किसी भी स्थिति तक पहुंचने की आवश्यकता नहीं है।

जैसा कि आप कहते हैं कि यह थ्रेड-सुरक्षित होना चाहिए - यदि अलग-अलग थ्रेड एक ही ऑब्जेक्ट पर सदस्य फ़ंक्शन को कॉल कर सकते हैं, तो आप शायद एक म्यूटेक्स का उपयोग करना चाहते हैं।boost::thread उपयोग करने के लिए एक अच्छी पुस्तकालय है।

+1

तो फ़ंक्शन ऑब्जेक्ट का एक गैर स्थैतिक सदस्य है क्योंकि यह पहले ऑब्जेक्ट (म्यूटेबल मैप) पर निर्भर करता था। एक स्थानीय स्थैतिक के साथ मैं इस समारोह को स्थैतिक बना सकता हूं। –

+0

ठीक है कि यह एक अलग बात है :) बस आपको इसके बारे में चेतावनी देना चाहता था अगर LongRunningOperation एक सदस्य फ़ंक्शन है जो आपकी ऑब्जेक्ट पर निर्भर करता है :) कोई भी सावधान नहीं रह सकता :) –