Clojure 的随机函数目前使用 {{Math.random}} 及相关功能,这使得它们无法进行设置。这似乎是使用动态 var(与额外参数相比)的一个适当用途,因为想要以随机方式行为的库代码可以透明地支持设置,而无需任何额外工作。
我在 {{clojure.core}} 中提出 {{(def ^:dynamic *rand* (java.util.Random.))}},并建议将 {{rand}}、{{rand-int}}、{{rand-nth}} 和 {{shuffle}} 更新以使用 {{*rand*}}。
我认为这在语义上不会是一个破坏性的更改。
二、基准测试
我进行了一些基准测试,试图了解使用动态 var 的性能影响,并衡量对并发访问的改变。
使用的代码在 [
https://github.com/gfredericks/clj-1452-tests;];;;;
{{rand}} 略慢,而 {{shuffle}} 则显著更快。在使用 8 个线程的 {{shuffle}} 中,没有显著的区别,但在修改版的补丁中手动切换到 {{ThreadLocalRandom}} 导致速度提高了 2.5 倍。
在我的 8 内核 Linode 虚拟机上运行
||基准||Clojure||运行时平均||运行时标准差||
|{{rand}}|1.6.0|61.3纳秒|7.06纳秒|
|{{rand}}|1.6.0 + {{*rand*}}|63.7纳秒|1.80纳秒|
|{{shuffle}}|1.6.0|12.9微秒|251纳秒|
|{{shuffle}}|1.6.0 + {{*rand*}}|12.8微秒|241纳秒|
|{{threaded-shuffling}}|1.6.0|151毫秒|2.31毫秒|
|{{threaded-shuffling}}|1.6.0 + {{*rand*}}|152毫秒|8.77毫秒|
|{{threaded-local-shuffling}}|1.6.0|N/A|N/A|
|{{threaded-local-shuffling}}|1.6.0 + {{*rand*}}|64.5毫秒|1.41毫秒|
方法:创建一个动态 var *rand* 并更新 {{rand}}、{{rand-int}}、{{rand-nth}} 和 {{shuffle}} 使用 *rand*
补丁:CLJ-1452.patch
审查: