Clojure 的随机函数目前使用 {{Math.random}} 及相关功能,这使得它们无法进行播种。这似乎是使用动态 var(相对于额外参数)的一个适当的用法,因为希望表现出随机性的库代码可以透明地支持播种,而不需要任何额外的工作。
我建议在 {{clojure.core}} 中定义 {{(def ^:dynamic *rand* (java.util.Random.))}},并更新 {{rand}}、{{rand-int}}、{{rand-nth}} 和 {{shuffle}} 以使用 {{*rand*}}。
我认为这从语义上来说不会是一个破坏性变更。
h2. Criterium 基准测试
我进行了一些基准测试,试图了解使用动态 var 的性能影响,以及衡量并发访问的变化。
使用的代码位于 [
https://github.com/gfredericks/clj-1452-tests];原始输出在注释中。
{{rand}} 略慢,而 {{shuffle}} 则微快。从 8 个线程使用 {{shuffle}} 略慢,但手动切换到修正版本中的 {{ThreadLocalRandom}} 可以带来 2.5 倍的速度提升。
在 8 核 Linode 虚拟机上运行
||基准测试||Clojure||运行平均时间||运行标准差||
|{{rand}}|1.6.0|61.3ns|7.06ns|
|{{rand}}|1.6.0 + {{*rand*}}|63.7ns|1.80ns|
|{{shuffle}}|1.6.0|12.9µs|251ns|
|{{shuffle}}|1.6.0 + {{*rand*}}|12.8µs|241ns|
|{{threaded-shuffling}}|1.6.0|151ms|2.31ms|
|{{threaded-shuffling}}|1.6.0 + {{*rand*}}|152ms|8.77ms|
|{{threaded-local-shuffling}}|1.6.0|N/A|N/A|
|{{threaded-local-shuffling}}|1.6.0 + {{*rand*}}|64.5ms|1.41ms|
*方法:创建一个动态 var *rand* 并更新 {{rand}}、{{rand-int}}、{{rand-nth}} 和 {{shuffle}} 以使用 {{*rand*}}
*修正:CLJ-1452.patch
*筛选:*