随机数 - 时间种子的方案与实践

文章探讨了如何在Lua中设置随机数种子以避免游戏开发中的错误,并解释了BT种子文件的工作原理和用途。此外,还讨论了时间种子的概念,以及使用当前时间戳作为随机数种子可能存在的问题,包括在同一秒内可能生成相同的随机数序列。文章提到了熵和不同来源的随机数生成,如/dev/random和/dev/urandom,以及在加密等安全场景下对随机数质量的要求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.应用场景

主要弄清楚设置随机数种子的方法,可用于游戏开发当中的时间种子从而产生合理的随机数,避免出现bug。

2.学习/操作

1.文档阅读

07 | 带你快速上手 Lua-极客时间

2.整理输出

2.1 什么是种子

现在很多朋友下载东西时都会用bt种子文件,那到底什么是bt种子文件呢?bt种子文件又是怎么用的呢?

种子是一个形象的比喻。其实bt种子文件就是记载下载文件的存放位置、大小、下载服务器的地址、发布者的地址等数据的一个索引文件。

这个种子文件并不是最终要下载的东西(如电影,软件,游戏等),但是要下载需要的东西,就必须先下载种子文件。种子文件的后缀名是:*.torrent。

什么是bt种子文件?

bt下载的原理,很复杂,简单说就是在下载的同时,也在上传。

BitTorrent(简称BT)是一个文件分发协议,它通过URL识别内容并且和网络无缝结合。BT首先在上传者端把一个文件分成了Z个部分,甲在服务器随机下载了第N个部分,乙在服务器随机下载了第M个部分,这样甲的BT就会根据情况到乙的电脑上去拿乙已经下载好的M部分,乙的BT就会根据情况去到甲的电脑上去拿甲已经下载好的N部分,这样就不但减轻了服务器端得负荷,也加快了用户方(甲乙)的下载速度,效率也提高了,更同样减少了地域之间的限制。比如说丙要连到服务器去下载的话可能才几K,但是要是到甲和乙的电脑上去拿就快得多了。所以说用的人越多,下载的人越多,大家也就越快,BT的优越性就在这里。而且,在下载的同时,你也在上传(别人从你的电脑上拿那个文件的某个部分),所以说在享受别人提供的下载的同时,你也在贡献。

BT把提供完整文件档案的人称为种子(SEED),正在下载的人称为客户(Client),某一个文件现在有多少种子多少客户是可以看到的,只要有一个种子,就可以放心地下载,一定能抓完。当然,种子越多、客户越多的文件抓起来的速度会越快。

「有人将原始发布信息的人成为种子,因为ta,才开出这么多的果实」

bt种子文件怎么用呢?

使用种子首先要有BT软件,然后就可以下载了!BT是一种类似与电驴的P2P共享软件,全名叫“BitTorrent”,中文全称:“比特流”,“变态”下载器是它的名字和下载率高的缘故,因此常人给它的一个化名。它是一种新的类似于P2P共享软件,因为每个下载的人同时又可以上传,下载的人越多,文件越大,速度就越快,而且只要普通的电脑接上网络就可以安装BT服务器。

目前最常用的就是迅雷下面以迅雷为例做讲解,bt种子文件的用法。

如果电脑里装了迅雷下载软件,那么只要双击bt种子文件就可以自动启用迅雷下载此种子文件所对应的文件(电影游戏等)。

或者打开迅雷,左上角部分有一个新建右面有一个倒立的黑小三角,点击一下。

出来一个打开bt种子,选择下来的种子所在的位置,就可以打开下载了。

其实就是可以类比生活中的种子:

就是可以用它来开花结果的原始的东西或者说,在它的基础上进行灌溉等一系列操作,最后得到的东西。

2.2 时间种子 

时间种子就是结合时间戳得到的一个希望的结果。

通常是为了区别不同的同类事物,比如得到某类事物的ID,name等。

2.3 方案

暂时先参考

网友:HelloBug
网上有种设置随机数种子的方法:
math.randomseed(tostring(os.time()):reverse():sub(1, 6))
即将时间值转换为字符串,然后将字符串倒序,然后取其前六位作为种子。之所以这样做的原因是因为当时间变化很小的时候,产生随机数的序列很相似。所以通过这种方法使得即使时间变化很小,由于reverse操作,时间的高位变成低位,低位变成高位,随机数种子的值变化会很大。

关于这种做法有以下两个问题:

1.当前执行os.time()打印的时间是1560251897,总共十位。认为函数中使用sub(1, 6)这里取前6位的中的6并不是一个固定的值,而且并没有什么意义,直接使用math.randomseed(tostring(os.time()):reverse())就能达到想要的效果。难道有其他我没有想到的原因?

2.这样的做法并不能阻止在同一秒内产生相同的随机数序列,如执行以下代码:
math.randomseed(tostring(os.time()):reverse():sub(1, 6)) 
print(math.random()) 
print(math.random())
math.randomseed(tostring(os.time()):reverse():sub(1, 6)) 
print(math.random()) 
print(math.random())
输出结果是:
0.49256881466135
0.0046852543018758
0.49256881466135
0.0046852543018758

另一种说法是对计算机的一些操作,如键盘、鼠标操作,会产生一些随机数,这些随机数叫熵。用户可以通过读取/dev/random和/dev/urandom文件来获取这些随机数。只不过读取/dev/random时,如果文件里的熵不足时会阻塞。读取/dev/urandom时,不会阻塞,但不能保证是合适的数据(熵不足时怎么处理未测试)。关于熵的还有其他相关知识,如通过操作鼠标、键盘等可以产生熵,通过cat /proc/sys/kernel/random/entropy_avail操作可以查看有多少熵可以用等。
这样的话,通过读取/dev/urandom设置随机数种子,是一种方法,但觉得这种文件读取操作,效率太低。

另外看留言里有人说通过系统调用,利用芯片电磁噪声来生成随机数。没有搜到是哪个系统调用。


作者回复: 很详细了。如果有加密的需求,从 /dev/random 和 /dev/urandom 读取会更安全,毕竟只是 init 的时候读取一次。

网友-HelloBug
返回三个变量,前两个变量重复使用同一个虚变量的例子:
resty -e 'local function sum(a, b) return a, b, a + b end local _, _, result = sum(1, 2) print(result)'

os.time返回当前时间的秒数,如果在同一秒内设置当前时间秒数为种子,然后执行随机数生成函数,产生的随机数序列是一样的。如:
resty -e 'math.randomseed(os.time()) print(math.random()) print(math.random()) math.randomseed(os.time()) print(math.random()) print(math.random())'
输出结果是:
0.71251659032569
0.36755092546457
0.71251659032569
0.36755092546457
可以看到两次产生的随机数序列相同。
作者回复: 👍

后续补充

...

3.问题/补充

1. chengzise

1. 用当前时间戳作为种子的,是通用做法没有什么大问题。这种方式利用的是随机数生成函数,随机数重复周期很长而已,不能算是完全随机。 大多数使用环境没什么问题。 2. 在要求严格随机数环境中,例如:加解密算法。可以使用系统提供的随机数接口,这种方式利用的是芯片电磁噪声来生成随机数。由于需要经过系统调用,理论上速度没有第一种方式快。 可以根据需要选择哪种方式。

作者回复: 就是要有足够的熵

后续补充

...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值