简体   繁体   English

Python缓存/存储和线程锁定

[英]Python cache/memorize and thread locking

When asked my application should open a .csv file make a dict from it. 当被问到我的应用程序应该打开一个.csv文件时,请从中做出决定。 I also need to cache that data and return from cache if its 'young' enough. 我还需要缓存该数据,如果足够“年轻”,则从缓存中返回。 Did that with a decorator: 用装饰器做了吗:

def memorize(key, period):
    """
    Memorizing decorator. Returning cached data
    if its validity period is not expired
    """
    def _decoration_wrapper(func):
        def _caching_wrapper(*args, **kwargs):
            cache_key = key
            now = time.time()

            if _timestamps.get(cache_key, now) > now:
                return _cache[cache_key]

            ret = func(*args, **kwargs)
            _cache[cache_key] = ret
            _timestamps[cache_key] = now + period
            return ret
        return _caching_wrapper
    return _decoration_wrapper

Works fine but i need to make it thread-safe. 工作正常,但我需要使其成为线程安全的。 I'd prefer to do it with the Lock class. 我更喜欢使用Lock类。 So i can be sure that in one period only one thread, one time will do the wrapped function. 因此,我可以确保在一个period只有一个线程一次可以完成包装功能。

So i want to now how to do that. 所以我现在想怎么做。
Info how to make tests would be very appreciated. 信息如何进行测试将不胜感激。
Much thanks. 非常感谢。

I would do this: 我会这样做:

import threading

#1
lock = threading.Lock() # use this line if theadsafety for _cache is important

def memorize(key, period):
    """
    Memorizing decorator. Returning cached data
    if its validity period is not expired
    """
    #2
    lock = threading.Lock() # use this line if theadsafety for a key is important
    def _decoration_wrapper(func):
        #3
        lock = threading.Lock() # use this line if theadsafety for  the function is important
        def _caching_wrapper(*args, **kwargs):
            cache_key = key
            now = time.time()

            if _timestamps.get(cache_key, now) > now:
                return _cache[cache_key]
            with lock:
                if _timestamps.get(cache_key, now) > now:
                    return _cache[cache_key]
                ret = func(*args, **kwargs)
                _cache[cache_key] = ret
                _timestamps[cache_key] = now + period
                return ret
        return _caching_wrapper
    return _decoration_wrapper

Line # : #

  1. you have got a shared ressource, the cache. 您有一个共享资源,即缓存。 It might be useful to lock this one. 锁定这一点可能会很有用。 It it is only a dictionairy then the GlobalInterpreterLock will do this for you. 只是字典,GlobalInterpreterLock会为您完成此操作。
  2. Lock the key. 锁住钥匙。 If two functions have the same decorator then they are not executed in parallel. 如果两个函数具有相同的装饰器,则不会并行执行它们。
  3. Lock the function. 锁定功能。 This means that a function will wait for the other calls to it in other threads to complete before it looks up the cache again. 这意味着一个函数将等待其他线程中对该函数的其他调用完成,然后再查找缓存。

How do you test this? 您如何测试呢? Write tests first, put in them more locks and timeouts to assure two functions are not executed at the same time. 首先编写测试,将更多的锁定和超时放入其中,以确保两个功能不能同时执行。 I do not have a general guide for it but these tests can be really ugly. 我没有通用的指南,但是这些测试确实很难看。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM