Clojure中的头部固位
在阅读“Clojure编程”(第98页)中关于头部保留的一段时,我无法理解使用示例拆分时会发生什么。我试着用repl做实验,但它让我更加困惑Clojure中的头部固位,clojure,Clojure,在阅读“Clojure编程”(第98页)中关于头部保留的一段时,我无法理解使用示例拆分时会发生什么。我试着用repl做实验,但它让我更加困惑 (time (let [r (range 1e7) a (take-while #(< % 12) r) b (drop-while #(< % 12) r)] [(count a) (count b)])) "Elapsed time: 1910.401711 msecs" [
(time (let [r (range 1e7)
a (take-while #(< % 12) r)
b (drop-while #(< % 12) r)]
[(count a) (count b)]))
"Elapsed time: 1910.401711 msecs"
[12 9999988]
(time (let [r (range 1e7)
a (take-while #(< % 12) r)
b (drop-while #(< % 12) r)]
[(count b) (count a)]))
"Elapsed time: 3580.473787 msecs"
[9999988 12]
(time (let [r (range 1e7)
a (take-while #(< % 12) r)
b (drop-while #(< % 12) r)]
[(count b)]))
"Elapsed time: 3516.70982 msecs"
[9999988]
(时间(让[r(范围1e7))
a(花时间#(<%12)r)
b(在#(<%12)r)时放下)]
[(计数a)(计数b)])
“运行时间:1910.401711毫秒”
[12 9999988]
(时间(let[r(范围1e7))
a(花时间#(<%12)r)
b(在#(<%12)r)时放下)]
[(b项)(a项)])
“运行时间:3580.473787毫秒”
[9999988 12]
(时间(let[r(范围1e7))
a(花时间#(<%12)r)
b(在#(<%12)r)时放下)]
[(计数b)])
“运行时间:3516.70982毫秒”
[9999988]
正如您从上一个示例中看到的,如果我不计算
a
,时间会以某种方式增长。我想,我错过了一些东西,但是什么呢?是O(1)。这就是为什么您的测量不依赖于它。绑定在中,让表单执行,即使我们不使用此值
(let [x (println "Side effect")] 1)
上面的代码打印“副作用”,并返回1
在所有三个示例中,都使用了相同的let形式绑定,因此我看不出有任何区别。顺便说一下,在我的机器上,你所有的代码片段花费的时间大致相等
当你尝试这样的事情时,真正的区别是:
(time (let [r (range 2e7)
a (take 100 r)
b (drop 100 r)]
[(count a)]))
"Elapsed time: 0.128304 msecs"
[100]
(time (let [r (range 2e7)
a (take 100 r)
b (drop 100 r)]
[(count b)]))
"Elapsed time: 3807.591342 msecs"
[19999900]
由于b
和a
是惰性序列,count
在O(n)
时间内工作。但在第一个例子中,我们不计算b的计数,所以它几乎可以立即工作 集合的count
函数为O(1),其中包括向量和列表
另一方面,序列是使它们计数的O(n)。这里的重要部分是函数在返回序列时执行
和在返回序列时执行。事实上,他们也是懒惰的,这并不是一个主要因素。当使用时间作为基准时,多次运行测试以获得准确的结果
user> (defn example2 [] (let [r (range 1e7)
a (take-while #(< % 12) r)
b (drop-while #(< % 12) r)]
[(count a) (count b)]))
#'user/example2
user> (dorun (take 1000 (repeatedly example2)))
nil
user> (time (example2))
"Elapsed time: 614.4 msecs"
[12 9999988]
user>(定义示例2[](let[r(范围1e7))
a(花时间#(<%12)r)
b(在#(<%12)r)时放下)]
[(计数a)(计数b)])
#'用户/示例2
用户>(多伦(取1000(重复示例2)))
无
用户>(时间(示例2))
“运行时间:614.4毫秒”
[12 9999988]
我指责运行时的差异,因为热点编译器尚未完全优化生成的类。我多次运行了第一个和第二个示例,得到了混合的相对结果:
运行示例1两次:
autotestbed.core> (time (let [r (range 1e7)
a (take-while #(< % 12) r)
b (drop-while #(< % 12) r)]
[(count a) (count b)]))
"Elapsed time: 929.681423 msecs"
[12 9999988]
autotestbed.core> (time (let [r (range 1e7)
a (take-while #(< % 12) r)
b (drop-while #(< % 12) r)]
[(count a) (count b)]))
"Elapsed time: 887.81269 msecs"
[12 9999988]
autotestbed.core>(时间(let[r(范围1e7))
a(花时间#(<%12)r)
b(在#(<%12)r)时放下)]
[(计数a)(计数b)])
“运行时间:929.681423毫秒”
[12 9999988]
自动测试。核心>(时间(let[r(范围1e7))
a(花时间#(<%12)r)
b(在#(<%12)r)时放下)]
[(计数a)(计数b)])
“运行时间:887.81269毫秒”
[12 9999988]
然后运行示例2几次:
core> (time (let [r (range 1e7)
a (take-while #(< % 12) r)
b (drop-while #(< % 12) r)]
[(count a) (count b)]))
"Elapsed time: 3838.751561 msecs"
[12 9999988]
core> (time (let [r (range 1e7)
a (take-while #(< % 12) r)
b (drop-while #(< % 12) r)]
[(count a) (count b)]))
"Elapsed time: 970.397078 msecs"
[12 9999988]
core>(时间(let[r(范围1e7))
a(花时间#(<%12)r)
b(在#(<%12)r)时放下)]
[(计数a)(计数b)])
“运行时间:3838.751561毫秒”
[12 9999988]
堆芯>(时间(let[r(范围1e7))
a(花时间#(<%12)r)
b(在#(<%12)r)时放下)]
[(计数a)(计数b)])
“运行时间:970.397078毫秒”
[12 9999988]
有些情况下,第二个示例同样快,它显示的时间完全取决于系统。。。。
如果重新执行,它将显示每次执行的不同运行时间列表计数实际上是O(1),但根据“Clojure编程”,seq不是真正的列表,获取seq的长度需要成本。抱歉。我误导了你。是的,在你的例子中是lazysek,“count”是O(n)。在我的机器上(计数a)花费了0.019毫秒。因此,对于您的测量,它仍然看起来像O(1)。请尝试检查(计数b),因为在我的情况下,它是(计数b),而不是(计数a)。基本上在(计数b)
之前使用(计数a)
导致原始示例中的总时间增加r
a
和b
在let语句中立即绑定到未计算的惰性序列。绑定这些名称不会导致对序列求值。这个问题与的问题重复,这给出了一个很好的答案。