Clojure 的随机函数目前使用 {{Math.random}} 和相关功能,这使得它们无法进行播种。这似乎是一个适当的使用动态 var 的例子(与额外参数相比),因为想要表现出随机行为的库代码可以透明地支持播种,而无需额外的工作。
我在 {{clojure.core}} 中提出将 {{(def ^:dynamic \*rand* (java.util.Random.))}},并且将 {{rand}}、{{rand-int}}、{{rand-nth}} 和 {{shuffle}} 更新为使用 {{\*rand*}}。
我认为这在语义上不会造成破坏性变化。
第2节:基准测试
我进行了一些基准测试,以尝试了解使用动态 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
*审查:**