线性全等生成器为Ruby on Rails中的Postgresql提供唯一的,非重复的随机数?

时间:2016-03-20 00:34:05

标签: ruby-on-rails ruby postgresql

我是否可以使用LCG(又名线性全等生成器)为我的员工提供 9位数,唯一但不重复的工作ID。

算法应使用BSD rand()公式,初始种子(状态0)为111,111,111,但将mod 2^31更改为mod 999,999,937

rand

但我是否必须始终从上次添加的工作人员中检索work ID以计算下一个?

请帮忙!

1 个答案:

答案 0 :(得分:2)

  

我可以使用LCG(也就是线性全等生成器)为我的员工提供9位数,唯一且不重复的工作ID。

这取决于你如何使用它。

如果你想为每个请求生成一个工作ID,那么不,你不能,因为

  

LCG不适合并行编程。多个线程可以同时访问当前存储的状态,从而导致竞争条件。在对不同线程使用相同初始化的实现中,在同时执行线程上可能出现相等的随机数序列。随机数生成器,尤其是并行计算机,不应该被信任。

(见Wikipedia

但是,您可以预先生成一堆工作ID,并为每位员工分配第一个未使用的工作ID。

例如,您可以使用db/seed.rb预先生成工作ID(假设您有AR模型WorkId

<强>分贝/ seed.rb

total_work_ids = 10_000  # based on how many potential employees
state = 111_111_111      # the seed

total_work_ids.times do
  state = (1_103_515_245 * state + 12345) % 999_999_937
  WorkId.create(value: '%09d' % state)
end

更新

使用数据库存储工作ID可能仍然存在竞争条件,因为每次获取新工作ID时,都需要一个查询(SELECT id, value FROM work_ids WHERE used = 0 LIMIT 1)和一个更新(UPDATE work_ids SET used = 1 WHERE id = ?),它&# 39;不是原子的。

我认为最好的解决方案是在Rails应用程序之外实现外部服务,该应用程序以先进先出的方式提供工作ID。这个服务应该很快,因为它被所有Rails线程/进程访问并阻塞它们。

我认为redis set是存储这些未使用的工作ID的好地方,因为它可以确保其中元素的唯一性,并且spop是原子的。