将“对象”添加到具有到期计时器的堆栈中,并在其到期时收到通知

时间:2011-04-05 14:44:58

标签: python caching

我需要在我的应用程序中保留一个对象(JSON)一段时间(通常为180秒)在某些时候,客户端可能会或可能不会返回并通过其密钥请求此对象。

棘手的部分是我需要在此对象过期时收到通知,因此如果客户端尚未请求它,我可以将其返回到可用池。

显而易见的解决方案是在数据库中使用类似时间戳的内容,然后使用定期脚本来检查过期项目,但这不是最好的解决方案。

理想情况下,我正在寻找像memcache这样的东西可以在一个项目到期时调用一个事件,肯定有这样的产品吗?

我目前的框架基于python,cherrpy,mongo,memcachce,但我很乐意添加它。

3 个答案:

答案 0 :(得分:1)

除非有其他进程将使用此对象池,否则在您需要分配一个对象之前,似乎没有理由将过期的对象返回到池中。如果检查过期对象并在分配新对象之前将它们返回到池中,则应该充分覆盖清理。

为了简化清理本身,请考虑创建(expire_time,object)元组列表并使用 bisect.insort()来保持列表按第一个值排序 - 过期时间:

que_tuple = (time.time() + EXPIRY_DELAY, obj)
bisect.insort(my_list, que_tuple)

每次去保留另一个对象时,都可以检查过期的项目是否返回到池中。通过使用排序列表,您只需检查第0个元素是否已过期,然后按顺序清除元素,直到找到未过期的元素。像这样:

time_to_act, obj = my_list[0]
while time.time() > time_to_act:
    return_to_pool( obj )   # whatever is necessary to clean-up your objects
    my_list.pop(0)
    time_to_act, obj = my_list[0]

如果确定您确实需要实现计时器,则此队列概念仍然有用。否则,您可以为每个对象的到期时间设置一个计时器。通常,可用的系统计时器数量有限,您可能会发现自己的资源不足。到期队列(my_list)允许单个计时器宣布下一个到期对象,并且计时器将重置为列表的新头部。

我希望这有帮助!

答案 1 :(得分:0)

我可能会使用threading.TimerTimer对象将在一段时间后使用给定的参数调用指定的函数。因此,编写一个将JSON对象返回给池的函数,并启动一个指定已保留的特定JSON对象的计时器。此外,您可以在计时器触发之前取消计时器,如果客户端在预订到期之前实际请求该对象,您将要执行该计时器。

为了跟踪池,我可能会使用dict,其中JSON对象是键,如果对象未签出,则值为None,或{{1实例,如果它被检出。可以使用单独的Timer来跟踪下一个应该发出的对象;当一个物体被取出时,从列表末尾开始list,当它返回时,pop()重新开始。请注意更新这两种结构的可能竞争条件!

答案 2 :(得分:-1)

我几乎可以肯定围绕redis expire命令的解决方案应该是必要的。它使用起来很简单。以下是使用Redis cli的示例。

redis> HMSET myhash field1 "Hello" field2 "World"
OK
redis> HGET myhash field1
"Hello"
redis> EXPIRE myhash 180
(integer) 1
redis> HGET myhash field2
"World"
redis> HGET myhash field2 # after 180 secs
(nil)

此外,Python有各种redis客户端选项。 redis-natives-py提供注释@temporary(after = None,at = None)。

通知部分

Redis不会通知你。可能是应用程序有逻辑假设在N秒后过期,是的,你可以随时用不昂贵的EXISTS命令确认。其他选择可能是使用greenlets来注意时间。就像它创建redis对象一样,睡眠N秒并唤醒确认redis并通知。我建议greenlet主要是因为它比Python线程更轻量级。