我有一个相对昂贵的数据获取操作,我想缓存结果。此操作从const方法调用,大致如下:

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

我希望AdjustData保持mutable map<int, double>,但我想要缓存因素,所以我只是第一次获取它。目前我正在使用key来存储结果(地图来自factor到<=>),但我认为使用函数范围的静态可能是一个更好的解决方案 - 只需要这个因素通过这个功能,与班上的其他人无关。

这看起来是一个好方法吗?还有更好的选择吗?我可以考虑哪些事情,特别是在线程安全方面。

谢谢,

的Dom

有帮助吗?

解决方案

我会用这样的东西包装LongRunningOperationToFetchFactor的实现。我正在使用Boost范围的锁,但你可以使用与其他锁定框架类似的东西。

#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是你的类的成员函数,那么你希望map在同一个类中是可变映射。我单个静态互斥锁用于访问仍然足够快。

其他提示

使此缓存成为本地静态。可变映射是用于缓存结果的 解决方案。否则它将使您的函数无用,因为类的不同对象将共享相同的缓存,因为本地静态缓存对于所有对象都是相同的。如果结果不依赖于对象,则可以使用本地静态。但是我会问自己为什么函数是你对象的非静态成员,如果它不需要访问它的任何状态。

正如你所说它应该是线程安全的 - 如果不同的线程可以在同一个对象上调用成员函数,你可能想要使用互斥锁。 boost::thread是一个很好的库。

您可以使用单身模式(1)与执行漫长的课程 - 运行操作并缓存结果。然后,此实例可用于其他类的const成员函数。考虑互斥以保护地图数据结构中的插入和提取以保证线程安全。如果多线程性能是一个大问题,那么您可以将密钥标记为正在进行中,以防止多个线程同时计算同一个密钥。

#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