如何用redis来生成唯一Id

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何用redis来生成唯一Id相关的知识,希望对你有一定的参考价值。

构造方法一:
public RedisAtomicLong(java.lang.String redisCounter,
RedisConnectionFactory factory)
1
2
1
2
该实例对应的自动增长的主键的key的名字为为redisCounter,如果redis中存在key的name为redisCounter的键值对,那么,则取其值;否则,将redisCounter对应的key值设置为0;

构造方法二:
public RedisAtomicLong(java.lang.String redisCounter,
RedisConnectionFactory factory,
long initialValue)
1
2
3
1
2
3
创建一个新的RedisAtomicLong实例,该实例对应的自动增长的主键的key的名字为为redisCounter,并将key name为redisCounter的值设置为initialValue;

RedisAtomicLong类有以下几个主要的方法:

方法一:
public long get();//返回当前的值
1
1
方法二:
public void set(long newValue);//设置当前实例的值为newValue
1
1
方法三:
public long incrementAndGet();//将当前实例的key值加一并且返回
1
1
那么,我们如何获得一个RedisAtomicLong实例呢?楼主提供以下两个方法:

在获取实例之前,我们需要设置好jedis的配置。
在application.xml文件中,加入以下配置:

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="$redis.pool.maxTotal" />
<property name="maxIdle" value="$redis.pool.maxIdle" />
<property name="testOnBorrow" value="$redis.pool.testOnBorrow" />
</bean>

<!-- jedis服务器配置 -->
<bean id="jedisShardInfo" class="redis.clients.jedis.JedisShardInfo">
<constructor-arg index="0" value="$redis.ip" />
<constructor-arg index="1" value="$redis.port" type="int" />
</bean>

<bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="$redis.ip" p:port="$redis.port" p:password="$redis.pass" p:pool-config-ref="jedisPoolConfig"/>

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnFactory"/>
<property name="keySerializer" ref="keySerializer"/>
<property name="enableTransactionSupport" value="false"/>
</bean>

<!-- redis 序列化-->
<bean id="keySerializer"
class="org.springframework.data.redis.serializer.StringRedisSerializer" />
参考技术A 系统唯一ID是我们在设计一个系统的时候常常会遇见的问题,也常常为这个问题而纠结。生成ID的方法有很多

如何用生成器中的值填充 2D Python numpy 数组?

【中文标题】如何用生成器中的值填充 2D Python numpy 数组?【英文标题】:How to fill a 2D Python numpy array with values from a generator? 【发布时间】:2017-09-18 01:55:57 【问题描述】:

根据here 的答案,似乎没有一种简单的方法可以用生成器中的数据填充二维 numpy 数组。

但是,如果有人能想到一种方法来矢量化或以其他方式加速以下功能,我将不胜感激。

这里的区别是我想批量处理来自生成器的值,而不是在内存中创建整个数组。我能想到的唯一方法是使用 for 循环。

import numpy as np
from itertools import permutations

permutations_of_values = permutations(range(1,20), 7)

def array_from_generator(generator, arr):
    """Fills the numpy array provided with values from
    the generator provided. Number of columns in arr
    must match the number of values yielded by the 
    generator."""
    count = 0
    for row in arr:
        try:
            item = next(generator)
        except StopIteration:
            break
        row[:] = item
        count += 1
    return arr[:count,:]

batch_size = 100000

empty_array = np.empty((batch_size, 7), dtype=int)
batch_of_values = array_from_generator(permutations_of_values, empty_array)

print(batch_of_values[0:5])

输出:

[[ 1  2  3  4  5  6  7]
 [ 1  2  3  4  5  6  8]
 [ 1  2  3  4  5  6  9]
 [ 1  2  3  4  5  6 10]
 [ 1  2  3  4  5  6 11]]

速度测试:

%timeit array_from_generator(permutations_of_values, empty_array)
10 loops, best of 3: 137 ms per loop

补充:

正如@COLDSPEED 所建议的(谢谢),这里是一个使用列表从生成器收集数据的版本。它大约是上面代码的两倍。任何人都可以对此进行改进:

permutations_of_values = permutations(range(1,20), 7)

def array_from_generator2(generator, rows=batch_size):
    """Creates a numpy array from a specified number 
    of values from the generator provided."""
    data = []
    for row in range(rows):
        try:
            data.append(next(generator))
        except StopIteration:
            break
    return np.array(data)

batch_size = 100000

batch_of_values = array_from_generator2(permutations_of_values, rows=100000)

print(batch_of_values[0:5])

输出:

[[ 1  2  3  4  5  6  7]
 [ 1  2  3  4  5  6  8]
 [ 1  2  3  4  5  6  9]
 [ 1  2  3  4  5  6 10]
 [ 1  2  3  4  5  6 11]]

速度测试:

%timeit array_from_generator2(permutations_of_values, rows=100000)
10 loops, best of 3: 85.6 ms per loop

【问题讨论】:

填写一个列表然后在结果上调用np.array应该更简单。 fromiter,正如在几个链接的答案中所讨论的,是直接从生成器的输出创建数组的唯一方法。否则,您需要创建一个列表并从中构建或填充数组。生成器可以在中间处理期间节省内存(参见等效的列表),但速度不会更快。 fromiter 会很棒,但它只适用于系列(一维数组)。 你能提前知道尺寸吗?那么你仍然可以使用fromiter 如果您阅读文档,它指出fromiter 创建“从可迭代对象创建新的一维数组”。我在这里尝试做的是二维的,因为生成器中的每个项目都是 7 个值的元组。也许是时候扩展fromiter 来处理多维迭代器了…… 【参考方案1】:

您可以在基本恒定的时间内计算出前面的尺寸。只需这样做,然后使用numpy.fromiter

In [1]: import math, from itertools import permutations, chain

In [2]: def n_chose_k(n, k, fac=math.factorial):
    ...:     return fac(n)/fac(n-k)
    ...:

In [3]: def permutations_to_array(r, k):
    ...:     n = len(r)
    ...:     size = int(n_chose_k(n, k))
    ...:     it = permutations(r, k)
    ...:     arr = np.fromiter(chain.from_iterable(it),
    ...:                       count=size,  dtype=int)
    ...:     arr.size = size//k, k
    ...:     return arr
    ...:

In [4]: arr = permutations_to_array(range(1,20), 7)

In [5]: arr.shape
Out[5]: (36279360, 7)

In [6]: arr[0:5]
Out[6]:
array([[ 1,  2,  3,  4,  5,  6,  7],
       [ 1,  2,  3,  4,  5,  6,  8],
       [ 1,  2,  3,  4,  5,  6,  9],
       [ 1,  2,  3,  4,  5,  6, 10],
       [ 1,  2,  3,  4,  5,  6, 11]])

只要r 仅限于带有len 的序列,这将起作用。

编辑添加了我为batchsize*k 块的生成器制作的实现,带有修剪选项!

import math
from itertools import repeat, chain

import numpy as np

def n_chose_k(n, k, fac=math.factorial):
    return fac(n)/fac(n-k)

def permutations_in_batches(r, k, batchsize=None, fill=0, dtype=int, trim=False):
    n = len(r)
    size = int(n_chose_k(n, k))
    if batchsize is None or batchsize > size:
        batchsize = size
    perms = chain.from_iterable(permutations(r, k))
    count = batchsize*k
    remaining = size - count
    while remaining > 0:
        current = np.fromiter(perms, count=count, dtype=dtype)
        current.shape = batchsize, k
        yield current
        remaining -= count
    if remaining: # remaining is negative
        remaining = -remaining
        if not trim:
            padding = repeat(fill, remaining)
            finalcount = count
            finalshape = batchsize, k
        else:
            q = remaining//k # always divisible q%k==0
            finalcount = q*k
            padding = repeat(fill, remaining)
            finalshape = q, k
        current =  np.fromiter(chain(perms, padding), count=finalcount, dtype=dtype)
        current.shape = finalshape
    else: # remaining is 0
        current = np.fromiter(perms, count=batchsize, dtype=dtype)
        current.shape = batchsize, k
    yield current

【讨论】:

n_chose_k 来自哪里? @Bill 对不起,忘了把它放在答案中 非常感谢。我认为结果数组的尺寸不太正确。不应该是count=size*karr.resize((size, k))吗? @Bill,根据我的经验,fromiter count 在运行时间上并没有太大区别。而arr.reshape(-1,k) 也不需要这个尺寸。 @Bill 如果你想看的话,最后会做一个有趣的事

以上是关于如何用redis来生成唯一Id的主要内容,如果未能解决你的问题,请参考以下文章

Redis 生成电商系统商品全局唯一 ID

Redis场景拓展秒杀问题-全局唯一ID生成策略

系统设计分布式唯一ID生成方案总结

如何用php生成一个16位数的id 并在指定的文件创建id文件夹

基于分布式锁 分布式全局唯一ID

Python uuid生成唯一ID