C ++에서 비싼 데이터 캐싱 - 함수 - 스코핑 된 정적 대 부패성 멤버 변수

StackOverflow https://stackoverflow.com/questions/614875

문제

결과를 캐시하고 싶은 비교적 비싼 데이터 페치 작업이 있습니다. 이 작업은 호출됩니다 const 방법, 대략 같은 방법 :

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

내가 좋아하는 것 AdjustData 남아 있습니다 const, 그러나 나는 요인을 캐시하고 싶다. 현재 나는 a를 사용하고있다 mutable map<int, double> 결과를 저장하려면 (지도가 key 에게 factor), 그러나 나는 함수 - 스코프 정적을 사용하는 것이 더 나은 솔루션 일 수 있다고 생각합니다.이 요소는이 기능에 의해서만 필요하며 나머지 클래스와 관련이 없습니다.

좋은 방법 인 것 같습니까? 더 나은 옵션이 있습니까? 특히 스레드 안전성과 관련하여 내가 어떻게 생각할 수 있는지.

감사,

도움이 되었습니까?

해결책

나는 LongrunningOperationToTchFactor의 구현을 이와 같은 것으로 마무리 할 것입니다. Boost Scoped Locks를 사용하고 있지만 다른 잠금 프레임 워크와 비슷한 것을 사용할 수 있습니다.

#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;
}

이것이 실제로 장기적인 운영이라면 뮤트를 잠그는 비용은 최소화되어야합니다.

질문에서 명확하지는 않았지만 LongRunningoperationTopetCFactor 함수가 귀하의 클래스의 멤버 함수 인 경우 동일한 클래스에서 MAP를 MAP BE BE BE BE BE 나는 액세스를위한 단일 정적 뮤 테스가 여전히 충분히 빠르다.

다른 팁

나는 할 것이다 ~ 아니다 이 캐시를 로컬 정적으로 만드십시오. 변한 맵은입니다 그만큼 캐싱 결과를위한 솔루션. 그렇지 않으면 로컬 정적 캐시가 모든 객체에 대해 동일하기 때문에 클래스의 다른 객체가 동일한 캐시를 공유하기 때문에 기능을 쓸모 없게 만듭니다. 결과가 객체에 의존하지 않으면 로컬 정적을 사용할 수 있습니다. 그러나 그 기능이 왜 그 상태에 액세스 할 필요가 없다면, 그 기능이 왜 당신의 객체의 비 정적 구성원인지 스스로에게 물어볼 것입니다.

당신이 말하는 것처럼 스레드 - 안전해야합니다 - 다른 스레드가 동일한 객체에서 멤버 함수를 호출 할 수 있다면 아마도 뮤텍스를 사용하려고합니다. boost::thread 사용하기에 좋은 도서관입니다.

당신은 사용할 수 있습니다 싱글 톤 패턴(1) 장기 실행 작업을 수행하고 결과를 캐시하는 클래스와 함께. 그런 다음이 인스턴스는 다른 클래스의 Const 회원 기능에서 사용할 수 있습니다. 스레드 안전을 위해 MAP 데이터 구조로부터 인서트 및 추출을 보호하기 위해 상호 배제를 고려하십시오. 다중 스레드 성능이 큰 문제인 경우, 여러 스레드가 동시에 동시에 동시에 계산하는 것을 방지하기 위해 진행중인 키를 플래그 할 수 있습니다.

#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) 싱글 톤 패턴은 크게 놓칠 수 있습니다. 그러니 처음보고 있다면 미치게하는 것을 삼가십시오.

내가 이해하지 못하면, 당신이 이것을 정적으로 만들고 싶어한다는 것이 분명해 보입니다.

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

그렇게하면 한 번만 요인 만 가져옵니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top