奇怪的aget优化行为 [英] Strange aget optimisation behavior

查看:196
本文介绍了奇怪的aget优化行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于 aget性能的问题的后续跟进

似乎有一些非常奇怪的优化进行。我们知道以下是真实的:

There seems to be something very strange going on optimisation wise. We knew the following was true:

=> (def xa (int-array (range 100000)))
#'user/xa

=> (set! *warn-on-reflection* true)
true

=> (time (reduce + (for [x xa] (aget ^ints xa x))))
"Elapsed time: 42.80174 msecs"
4999950000

=> (time (reduce + (for [x xa] (aget xa x))))
"Elapsed time: 2067.673859 msecs"
4999950000
Reflection warning, NO_SOURCE_PATH:1 - call to aget can't be resolved.
Reflection warning, NO_SOURCE_PATH:1 - call to aget can't be resolved.

但是,一些进一步的试验真的让我很奇怪:

However, some further experimenting really weirded me out:

=> (for [f [get nth aget]] (time (reduce + (for [x xa] (f xa x)))))
("Elapsed time: 71.898128 msecs"
"Elapsed time: 62.080851 msecs"
"Elapsed time: 46.721892 msecs"
4999950000 4999950000 4999950000)

无反射警告,无需提示。通过将aget绑定到根var或在let中可以看到相同的行为。

No reflection warnings, no hints needed. Same behavior is seen by binding aget to a root var or in a let.

=> (let [f aget] (time (reduce + (for [x xa] (f xa x)))))
"Elapsed time: 43.912129 msecs"
4999950000

任何想法为什么绑定aget似乎知道如何优化,核心功能不在哪里?

Any idea why a bound aget seems to 'know' how to optimise, where the core function doesn't ?

推荐答案

它与:inline 指令 / code>,它扩展为(。clojure.lang.RT(aget〜a(int〜i)),而正常函数调用涉及 Reflector 。尝试这些:

It has to do with the :inline directive on aget, which expands to (. clojure.lang.RT (aget ~a (int ~i)), whereas the normal function call involves the Reflector. Try these:

user> (time (reduce + (map #(clojure.lang.Reflector/prepRet 
       (.getComponentType (class xa)) (. java.lang.reflect.Array (get xa %))) xa)))
"Elapsed time: 63.484 msecs"
4999950000
user> (time (reduce + (map #(. clojure.lang.RT (aget xa (int %))) xa)))
Reflection warning, NO_SOURCE_FILE:1 - call to aget can't be resolved.
"Elapsed time: 2390.977 msecs"
4999950000

那么,你可能会想知道内联的意义。好,看看这些结果:

You might wonder what's the point of inlining, then. Well, check out these results:

user> (def xa (int-array (range 1000000))) ;; going to one million elements
#'user/xa
user> (let [f aget] (time (dotimes [n 1000000] (f xa n))))
"Elapsed time: 187.219 msecs"
user> (time (dotimes [n 1000000] (aget ^ints xa n)))
"Elapsed time: 8.562 msecs"

事实证明,在你的例子中,一旦你遇到反射警告,你的新瓶颈是 reduce + 部分而不是数组访问。此示例消除了这一点,并显示了类型提示的内联 aget 的有序数量级优势。

It turns out that in your example, as soon as you get past reflection warnings, your new bottleneck is the reduce + part and not array access. This example eliminates that and shows an order-of-magnitude advantage of the type-hinted, inlined aget.

这篇关于奇怪的aget优化行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆