我是否可以使用LCG(又名线性全等生成器)为我的员工提供 9位数,唯一但不重复的工作ID。
算法应使用BSD rand()
公式,初始种子(状态0)为111,111,111,但将mod 2^31
更改为mod 999,999,937
:
但我是否必须始终从上次添加的工作人员中检索work ID
以计算下一个?
请帮忙!
答案 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
是原子的。