J

计数器(counter)

应用

计数器一般用于访问量、下载量、投票数等各种计数用途,和自增唯一id(autoincrementing unique identifier)不同的是,计数器的值不但可以被增加,还可以被清零(比如发现有作弊行为),或者被减少(比如部分计数无效),所以计数器生成的值也不是唯一的。

定义

一个计数器,至少应该拥有以下四个操作:

  1. 增加数值
  2. 减少数值
  3. 清零
  4. 查看当前数值

实现

计数器可以用以下两种方式实现:

  1. String类函数,INCRINCRBYDECRDECRBY,还有GETSET
  2. Hash类函数,HINCRBYHSETHGET

String实现

# coding:utf-8

# file: ./j/counter/string_implement.py

from redis import Redis

INITIAL_VALUE = 0

class Counter:
    
    def __init__(self, name, client=Redis()):
        self.name = name
        self.client = client

    def incr(self, increment=1):
        # redis-py 用 incr 代替 incrby,所以可以指定增量
        value = self.client.incr(self.name, increment)
        return int(value)

    def decr(self, decrement=1):
        # redis-py 用 decr 代替 decrby,所以可以指定减量
        value = self.client.decr(self.name, decrement)
        return int(value)

    def set(self, value):
        self.client.set(self.name, value)

    def get(self):
        value = self.client.get(self.name)
        return INITIAL_VALUE if value is None else int(value)

    def reset(self):
        self.set(INITIAL_VALUE)

Hash实现

Hash实现和String实现稍有不同,Hash实现还需提供一个key作Hash的键。另外,Hash只有HINCRBY而没有HDECRBY命令,但是我们可以通过代码0-decrement将负数作为“增量”,传入HINCRBY命令,来达到做减法的效果。

# file: ./j/counter/hash_implement.py

from redis import Redis

INITIALI_VALUE = 0
KEY = 'counter'

class Counter:
    
    def __init__(self, field, client=Redis(), key=KEY):
        self.key = key
        self.field = field
        self.client = client

    def incr(self, increment=1):
        value = self.client.hincrby(self.key, self.field, increment)
        return int(value)

    def decr(self, decrement=1):
        value = self.client.hincrby(self.key, self.field, 0-decrement)
        return int(value)

    def set(self, value):
        self.client.hset(self.key, self.field, value)

    def get(self):
        value = self.client.hget(self.key, self.field)
        return INITIALI_VALUE if value is None else int(value)

    def reset(self):
        self.set(INITIALI_VALUE)