- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
几天前,我创建了一个简单的基准测试(没有 jmh 和所有其他专门的东西,只是为了粗略测量)。
我发现对于相同的简单任务(遍历 1000 万个数字,对它们求平方,仅过滤偶数并减少它们的总和),Java 的运行速度要快得多。这是代码:
Kotlin :
fun test() {
println((0 .. 10_000_000L).map { it * it }
.filter { it % 2 == 0L }
.reduce { sum, it -> sum + it })
}
Java:
public void test() {
System.out.println(LongStream.range(0, 10_000_000)
.map(it -> it * it)
.filter(it -> it % 2 == 0)
.reduce((sum, it) -> sum + it)
.getAsLong());
}
我使用的是 Java 1.8.0_144 版和 Kotlin 1.2 版。
在我的硬件上,Java 平均需要 85ms,Kotlin 需要 4,470ms 来执行相应的功能。 Kotlin 的运行速度慢了 52 倍。
我怀疑 Java 编译器会生成优化的字节码,但我没想到会看到如此巨大的差异。我想知道我是否做错了什么?我怎样才能迫使 Kotlin 工作得更快?我喜欢它是因为它的语法,但 52 次是一个很大的不同。而且我只是编写了类似 Java 8 的代码,而不是普通的旧迭代版本(我相信它会比给定的版本快得多)。
最佳答案
当您将苹果与橙子进行比较时,结果并不能告诉您太多信息。您将一个 API 与另一个 API 进行了比较,每个 API 都有完全不同的重点和目标。
由于 JDK 的所有部分与特定于 Kotlin 的添加一样都是“Kotlin”,因此我写了更多的同类比较,这也解决了一些“JVM 微基准测试”问题。
Kotlin :
fun main(args: Array<String>) {
println("Warming up Kotlin")
test()
test()
test()
println("Measuring Kotlin")
val average = (1..10).map {
measureTimeMillis { test() }
}.average()
println("An average Kotlin run took $average ms")
println("(sum is $sum)")
}
var sum = 0L
fun test() {
sum += LongStream.range(0L, 100_000_000L)
.map { it * it }
.filter { it % 2 == 0L }
.reduce { sum, it -> sum + it }
.asLong
}
Java:
public static void main(String[] args) {
System.out.println("Warming up Java");
test();
test();
test();
System.out.println("Measuring Java");
LongSummaryStatistics stats = LongStream.range(0, 10)
.map(i -> measureTimeMillis(() -> test()))
.summaryStatistics();
System.out.println("An average Java run took " + stats.getAverage() + " ms");
System.out.println("sum is " + sum);
}
private static long sum;
private static void test() {
sum += LongStream.range(0, 100_000_000)
.map(it -> it * it)
.filter(it -> it % 2 == 0)
.reduce((sum, it) -> sum + it)
.getAsLong();
}
private static long measureTimeMillis(Runnable measured) {
long start = System.nanoTime();
measured.run();
return TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
}
我的结果:
Warming up Kotlin
Measuring Kotlin
An average Kotlin run took 158.5 ms
(sum is 4276489111714942720)
Warming up Java
Measuring Java
An average Java run took 357.3 ms
sum is 4276489111714942720
惊讶?我也是。
与其进一步挖掘,试图弄清楚预期结果的这种反转,我想得出这样的结论:
Kotlin 在 Iterable
上的 FP 扩展是为了方便起见。在 95% 的所有用例中,您不关心在 10-100 个元素的列表上执行快速映射过滤器是否需要 1 或 2 微秒。
Java 的 Stream API 专注于对大型数据结构进行批量操作的性能。它还为同一目标提供自动并行化(尽管它几乎从来没有真正帮助过),但由于这些问题,它的 API 是有缺陷的,有时甚至很尴尬。例如,许多有用的操作恰好没有很好地并行化,并且不存在,并且非终端与终端操作的整个范例增加了您编写的每个 Streams 表达式的体积。
让我再谈谈你的一些陈述:
I know that the Java compiler produces optimized bytecode
这是 a) 不正确的,b) 很大程度上无关紧要,因为(几乎)没有“优化字节码”这样的东西。字节码的解释执行总是比 JIT 编译的 native 代码至少慢一个数量级。
And I just wrote Java 8-like code, not the plain old iterative version (which, I believe, will be much faster than given one).
你是这个意思吗?
Kotlin :
fun test() {
var sum: Long = 0
var i: Long = 0
while (i < 100_000_000) {
val j = i * i
if (j % 2 == 0L) {
sum += j
}
i++
}
total += sum
}
Java:
private static void test() {
long sum = 0;
for (long i = 0; i < 100_000_000; i++) {
long j = i * i;
if (j % 2 == 0) {
sum += j;
}
}
total += sum;
}
结果如下:
Warming up Kotlin
Measuring Kotlin
An average Kotlin run took 150.1 ms
(sum is 4276489111714942720)
Warming up Java
Measuring Java
An average Java run took 153.0 ms
sum is 4276489111714942720
在这两种语言中,性能几乎与上面的 Kotlin + Streams API 相同。如前所述,Streams API 针对性能进行了优化。
kotlinc
和 javac
都可能生成非常相似的字节码,给定这个简单的源代码,然后 HotSpot 以相同的方式完成它的工作。
关于java - 为什么 Kotlin map-filter-reduce 在大输入上比 Java Stream 操作慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48317709/
自己试试看: import pandas as pd s=pd.Series(xrange(5000000)) %timeit s.loc[[0]] # You need pandas 0.15.1
我最近开始使用 Delphi 中的 DataSnap 来生成 RESTful Web 服务。在遵循 Marco Cantu 本人和互联网上其他几个人的指导后,我成功地使整个“链条”正常工作。 但是有一
我一直在为操作系统类(class)编写以下代码,但结果有些奇怪。该代码创建x线程并同时运行它们,以便将两个平方矩阵相乘。每个线程将输入矩阵的Number_of_rows/Number_of_threa
我正在尝试确定何时使用 parallel包以加快运行某些分析所需的时间。我需要做的一件事是创建矩阵,比较具有不同行数的两个数据框中的变量。我在 StackOverflow 上问了一个关于有效方法的问题
我最近对我的代码进行了一些清理,并在此过程中更改了此内容(不完全是真实的代码): read = act readSTRef test1 term i var = do t v^!terms.
我正在计时查询和同一个查询的执行时间,分页。 foreach (var x in productSource.OrderBy(p => p.AdminDisplayName) .Wher
我正在开发一个项目 (WPF),我有一个 Datagrid 从数据库加载超过 5000 条记录,所以我使用 BackgroundWorker 来通知用户数据正在加载,但它太慢了,我需要等待将近 2分钟
我在查询中添加 ORDER BY 时遇到问题。没有 ORDER BY 查询大约需要 26ms,一旦我添加 ORDER BY,它大约需要 20s。 我尝试了几种不同的方法,但似乎可以减少时间。 尝试 F
我是 Android 开发新手,遇到了性能问题。当我的 GridView 有太多项目时,它会变得有点慢。有什么方法可以让它运行得更快一些吗? 这是我使用的代码: 适配器: public class C
这里的要点是: 1.设置query_cache_type = 0;重置查询缓存; 2.在 heidisql(或任何其他客户端 UI)中运行任何查询 --> 执行,例如 45 毫秒 3.使用以下代码运行
想象下表: CREATE TABLE drops( id BIGSERIAL PRIMARY KEY, loc VARCHAR(5) NOT NULL, tag INT NOT
我的表 test_table 中的示例数据: date symbol value created_time 2010-01-09 symbol1
首先,如果已经有人问过这个问题,我深表歉意,至少我找不到任何东西。 无论如何,我将每 5 分钟运行一次 cron 任务。该脚本加载 79 个外部页面,而每个页面包含大约 200 个我需要在数据库中检查
我有下面的 SQL 代码,它来自 MySQL 数据库。现在它给了我期望的结果,但是查询很慢,我想我应该在进一步之前加快这个查询的速度。 表agentstatusinformation有: PKEY(主
我需要获取一个对象在 Core Data 中数千个其他对象之间的排名。现在,这是我的代码: - (void)rankMethod { //Fetch all objects NSFet
我正在编写一个应用程序,我需要在其中读取用户的地址簿并显示他所有联系人的列表。我正在测试的 iPhone 有大约 100 个联系人,加载联系人确实需要很多时间。 ABAddressBookRef ad
我正在使用 javascript 将 160 行添加到包含 10 列的表格中。如果我这样做: var cellText = document.createTextNode(value); cell.a
我是 Swift 的新手,我已经设置了一个 tableView,它从 JSON 提要中提取数据并将其加载到表中。 表格加载正常,但是当表格中有超过 10 个单元格时,它会变得缓慢且有些滞后,特别是它到
我在 InitializeCulture 和 Page_PreInit 事件之间的 asp.net 页面中遇到性能问题。当我重写 DeterminePostBackMode() 时,我发现问题出在 b
我在 Hetzner 上有一个带有 256GB RAM 6 个 CPU(12 个线程) 的专用服务器,它位于德国。我有 CENTOS 7.5。 EA4。 我的问题是 SSL。每天大约 2 小时,我们在
我是一名优秀的程序员,十分优秀!