在Clojure中快速生成随机字符串

huangapple go评论71阅读模式
英文:

Fast random string generator in Clojure

问题

我在想是否有一种方法可以在Clojure中生成固定长度的随机字符串。

经过快速搜索,得到了以下结果:

(defn rand-str [len]
  (apply str (take len (repeatedly #(char (+ (rand 26) 65))))))

在查看了VisualVM的CPU性能数据之后,我意识到它消耗了相当多的CPU资源:

在Clojure中快速生成随机字符串

因此,我决定将其重写,使其类似于我曾经使用的Java函数:

(defn rand-str2-slow
  ^String [^Long len]
  (let [leftLimit 97
        rightLimit 122
        random (Random.)
        stringBuilder (StringBuilder. len)
        diff (- rightLimit leftLimit)]
    (dotimes [_ len]
      (let [ch (char (.intValue (+ leftLimit (* (.nextFloat random) (+ diff 1)))))])
      (.append stringBuilder ch)))
  (.toString stringBuilder)))

然而,这导致了更慢的代码,不过堆栈跟踪的深度要少得多:

在Clojure中快速生成随机字符串

我注意到它执行了很多Reflector.getMethods()。是否有办法对该函数进行类型提示,以避免这种情况?

更新1:

相关微基准测试:

rand-str

(with-progress-reporting (quick-bench (rand-str 5000) :verbose))
  
      Execution time sample mean : 1.483232 ms
             Execution time mean : 1.483547 ms
Execution time sample std-deviation : 31.161960 µs
    Execution time std-deviation : 31.651732 µs
   Execution time lower quantile : 1.441678 ms ( 2.5%)
   Execution time upper quantile : 1.531289 ms (97.5%)
                   Overhead used : 14.598226 ns

rand-str2-slow

(with-progress-reporting (quick-bench (rand-str2-slow 5000) :verbose))
  
      Execution time sample mean : 17.637256 ms
             Execution time mean : 17.647974 ms
Execution time sample std-deviation : 523.527242 µs
    Execution time std-deviation : 528.559280 µs
   Execution time lower quantile : 17.322583 ms ( 2.5%)
   Execution time upper quantile : 18.522246 ms (97.5%)
                   Overhead used : 14.598226 ns

rand-str2(快速版本)

(with-progress-reporting (quick-bench (rand-str2 5000) :verbose))
  
      Execution time sample mean : 84.362974 µs
             Execution time mean : 84.355379 µs
Execution time sample std-deviation : 3.496944 µs
    Execution time std-deviation : 3.674542 µs
   Execution time lower quantile : 80.911920 µs ( 2.5%)
   Execution time upper quantile : 89.264431 µs (97.5%)
                   Overhead used : 14.598226 ns
英文:

I was wondering if there is a way to generate a fixed length random string in Clojure.

A quick search resulted in:

https://gist.github.com/rboyd/5053955

(defn rand-str [len]
  (apply str (take len (repeatedly #(char (+ (rand 26) 65))))))

After I had a look at the VisualVM CPU profile data I realized that is consumes a non-trivial amount of CPU:

在Clojure中快速生成随机字符串

I decided to rewrite it be similar to the Java function I have used to use:

(defn rand-str2-slow
  ^String [^Long len]
  (let [leftLimit 97
        rightLimit 122
        random (Random.)
        stringBuilder (StringBuilder. len)
        diff (- rightLimit leftLimit)]
    (dotimes [_ len]
      (let [ch (char (.intValue (+ leftLimit (* (.nextFloat random) (+ diff 1)))))]
        (.append stringBuilder ch)))
        (.toString stringBuilder)))

This resulted in even slower code, however the stack trace has much less depth:

在Clojure中快速生成随机字符串

I noticed it does a lot of Reflector.getMethods(). Is there a way to type hint the function to avoid that?

UPDATE1:

Relevant microbenchmarks:

rand-str

(with-progress-reporting (quick-bench (rand-str 5000) :verbose))

      Execution time sample mean : 1.483232 ms
             Execution time mean : 1.483547 ms
Execution time sample std-deviation : 31.161960 µs
    Execution time std-deviation : 31.651732 µs
   Execution time lower quantile : 1.441678 ms ( 2.5%)
   Execution time upper quantile : 1.531289 ms (97.5%)
                   Overhead used : 14.598226 ns

rand-str2-slow

(with-progress-reporting (quick-bench (rand-str2-slow 5000) :verbose))

      Execution time sample mean : 17.637256 ms
             Execution time mean : 17.647974 ms
Execution time sample std-deviation : 523.527242 µs
    Execution time std-deviation : 528.559280 µs
   Execution time lower quantile : 17.322583 ms ( 2.5%)
   Execution time upper quantile : 18.522246 ms (97.5%)
                   Overhead used : 14.598226 ns

rand-str2 (fast)

(with-progress-reporting (quick-bench (rand-str2 5000) :verbose))

      Execution time sample mean : 84.362974 µs
             Execution time mean : 84.355379 µs
Execution time sample std-deviation : 3.496944 µs
    Execution time std-deviation : 3.674542 µs
   Execution time lower quantile : 80.911920 µs ( 2.5%)
   Execution time upper quantile : 89.264431 µs (97.5%)
                   Overhead used : 14.598226 ns

答案1

得分: 4

让我回答自己的问题:

(defn rand-str2
  ^String [^Long len]
  (let [leftLimit 97
        rightLimit 122
        random (Random.)
        stringBuilder (StringBuilder. len)
        diff (- rightLimit leftLimit)]
    (dotimes [_ len]
      (let [ch (char (.intValue ^Double (+ leftLimit (* (.nextFloat ^Random random) (+ diff 1)))))])
      (.append ^StringBuilder stringBuilder ch)))
      (.toString ^StringBuilder stringBuilder)))
英文:

Let me answer my own question:

(defn rand-str2
  ^String [^Long len]
  (let [leftLimit 97
        rightLimit 122
        random (Random.)
        stringBuilder (StringBuilder. len)
        diff (- rightLimit leftLimit)]
    (dotimes [_ len]
      (let [ch (char (.intValue ^Double (+ leftLimit (* (.nextFloat ^Random random) (+ diff 1)))))]
        (.append ^StringBuilder stringBuilder ch)))
        (.toString ^StringBuilder stringBuilder)))

huangapple
  • 本文由 发表于 2020年9月24日 03:09:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/64034761.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定