一个清除数组的方法在 Kotlin、Java、C#和Nim上的性能测试
起因
我的一个项目使用 Kotlin 编写,他是一个多维数据库应用程序,所以会非常频繁的操作 int 数组,其中有段程序就需要进行 几亿次的数组清除动作,类似这样的代码:
Arrays.fill(target, 0);
这个Arrays.fill其实就是jdk自带的一个实现,非常简陋,就是一个for循环填充数据。
所以我想改进他,将常见的数组长度编写成单个的实现,比如清除8个长度的方法如下:
fun clear8(target: IntArray) {
if(target.size < 8){
throw IndexOutOfBoundsException()
}
target[0] = 0
target[1] = 0
target[2] = 0
target[3] = 0
target[4] = 0
target[5] = 0
target[6] = 0
target[7] = 0
}
不要怀疑你的眼睛,这样的写法通常是有效的。好的编译器会优化我写的代码,当然,更好的编译器会优化一个简单数组的for循环,这是后话。
那我们就测试一下吧。
import java.util.*
import kotlin.system.measureNanoTime fun main() {
test3()
} private fun test3() {
val size = 8
val time2 = measureNanoTime {
val target = IntArray(size)
for (i in 0 until 10_0000_0000) {
IntArrays.clear8(target)
}
}
println("fill$size $time2") val time1 = measureNanoTime {
val target = IntArray(size)
for (i in 0 until 10_0000_0000) {
Arrays.fill(target, 0)
}
}
println("Arrays.fill$size $time1")
println()
} internal object IntArrays {
fun clear8(target: IntArray) {
if(target.size < 8){
throw IndexOutOfBoundsException()
}
target[0] = 0
target[1] = 0
target[2] = 0
target[3] = 0
target[4] = 0
target[5] = 0
target[6] = 0
target[7] = 0
}
}
测试结果:
fill8 55,408,200
Arrays.fill8 2,262,171,100
可以看出,使用展开的方式,比java自带的2.2秒,性能提高了40倍!!
与Java的性能对比
我感叹kotlin的编译器真的很强,但仔细一想,不对啊, Kotlin 就是基于 JVM 的,功劳应该是 java 的虚拟机运行时很厉害,所以如果这个程序如果转化为java直接编写是不是更快,至少性能一致吧。说干就干。
//IntArrays.java
import java.util.Arrays; final class IntArrays {
static void clear8(int[] target) {
/* if (target.length < 8){
throw new IndexOutOfBoundsException();
}*/
target[0] = 0;
target[1] = 0;
target[2] = 0;
target[3] = 0;
target[4] = 0;
target[5] = 0;
target[6] = 0;
target[7] = 0;
}
} // IntArraysDemoJava.java
import java.util.Arrays; public final class IntArraysDemoJava {
public static void main(String[] var0) {
test1();
} private static void test1() {
long count = 1000000000;
long start = System.nanoTime();
final int[] target = new int[8]; for(int i = 0; i < count; i++) {
IntArrays.clear8(target);
}
long time2 = System.nanoTime() - start;
System.out.println("fill8 " + time2); start = System.nanoTime();
for(int i = 0; i < count; i++) {
Arrays.fill(target, 0);
} long time1 = System.nanoTime() - start;
System.out.println("Arrays.fill8 " + time1);
System.out.println();
}
}
Java的实现
测试结果如下:
fill8 2,018,500,800
Arrays.fill8 2,234,306,500
天啊,在java下这种优化几乎没有效果,java我没有找到什么 release编译参数的概念,最多只有debug = false,我是在gradle中包含
compileJava {
options.debug = false
}
那么就是说,Kotlin生成的字节码要好于 Java生成的字节码?
Java Kotlin
ALOAD 0 ALOAD 1
ICONST_0 ICONST_0
ICONST_0 ICONST_0
IASTORE ASTORE ALOAD 0 ALOAD 1
ICONST_1 ICONST_1
ICONST_0 ICONST_0
IASTORE IASTORE
字节码稍微不同,你要是问我为什么? 我母鸡啊。。。。。。
与C# 的对比
作为一个 .net 的死忠粉,这个时候就会想着是不是 c# 更快一些,更何况 .net core 3做了大量的性能优化,
class Program {
static void Main(string[] args) {
Test3.test1();
}
}
class Test3
{
public static void test1()
{
long count = 1000000000;
var watch = System.Diagnostics.Stopwatch.StartNew();
int[] target = new int[8];
for (int i = 0; i < count; i++)
{
Clear8(target);
}
watch.Stop();
Console.WriteLine("fill8 " + watch.Elapsed);
watch.Restart();
for (int i = 0; i < count; i++)
{
Array.Clear(target, 0,8);
}
watch.Stop();
Console.WriteLine("Array.Clear8 " + watch.Elapsed);
Console.WriteLine();
}
static void Clear8(int[] target)
{
/* if (target.Length < 8)
{
throw new IndexOutOfRangeException();
}*/
target[0] = 0;
target[1] = 0;
target[2] = 0;
target[3] = 0;
target[4] = 0;
target[5] = 0;
target[6] = 0;
target[7] = 0;
}
}
测试成绩:
fill8 00:00:02.7462676
Array.Clear8 00:00:08.4920514
和Java比起来还要慢,甚至系统自带的Array.clear更加慢,这怎么能让我忍,于是一通的 Span.Fill(0),结果更不理想。
和Nim对比的性能
兴趣提起来了,那就使用C语言实现一个....... 没写出来,我笨......,那就使用 Rust 实现一个,还是没有实现出来,按照教程一步步写,还是没有搞定..........
最后折腾出来一个 Nim 环境,嗯,还是这个简单。
import times, strutils proc clear8*[int](target: var seq[int]) =
target[0] = 0
target[1] = 0
target[2] = 0
target[3] = 0
target[4] = 0
target[5] = 0
target[6] = 0
target[7] = 0 proc clear*[int](target: var seq[int]) =
for i in 0..<target.len:
target[i] = 0 proc test3() =
const size = 8
var start = epochTime()
var target = newseq[int](size)
for i in 0..<10_0000_0000:
target.clear8() let elapsedStr = (epochTime() - start).formatFloat(format = ffDecimal, precision = 3)
echo "fill8 ", elapsedStr start = epochTime()
for i in 0..<10_0000_0000:
target.clear() let elapsedStr2 = (epochTime() - start).formatFloat(format = ffDecimal, precision = 3)
echo "Arrays.fill ", elapsedStr2 test3()
Nim
测试成绩,注意要加 --release 参数。
fill8 3.499
Arrays.fill 5.825
失望,及其失望。
备注
所有测试是在我的台式机上进行的,配置如下:
AMD Ryzen 5 3600 6 Core 3.59 Ghz
8 GB RAM
Windows 10 64 专业版
所有测试都使用release编译。
一个清除数组的方法在 Kotlin、Java、C#和Nim上的性能测试的更多相关文章
- java中远程http文件上传及file2multipartfile
工作中有时会遇到各种需求,你得变着法儿去解决,当然重要的是在什么场景中去完成. 比如Strut2中file类型如何转换成multipartfile类型,找了几天,发现一个变通的方法记录如下(虽然最后没 ...
- atitit.技术选型方法总结为什么java就是比.net有前途
atitit.技术选型方法总结为什么java就是比.net有前途 #----按照不同的需要有不铜的法... 一般有开发效率,稳定性上的需要.. 作者 老哇的爪子 Attilax 艾龙, EMAIL: ...
- Ant执行一个含有main方法的class文件
目前需要使用ant来执行一个含有main方法的class文件,并且需要通过命令来行传两个参数(start和end)到main方法. <target name="gsp" de ...
- 一个Web Project引用多个Java Project在Eclipse下的配置--转载
项目结构: 项目由一个Web Project和多个Java Project构成,Web Project需要引用其它Java Project的类和Jar包.开发时用Eclipse3.5和Tomcat调试 ...
- Bean-Query 一个把对象转换为Map的Java工具库
刚开源了一个经过完整測试的Java工具类. 地址例如以下: https://github.com/Jimmy-Shi/bean-query 使用说明例如以下: Bean-query Click Her ...
- Java-Runoob-高级教程-实例-方法:14. Java 实例 – Varargs 可变参数使用
ylbtech-Java-Runoob-高级教程-实例-方法:14. Java 实例 – Varargs 可变参数使用 1.返回顶部 1. Java 实例 - Varargs 可变参数使用 Java ...
- Java-Runoob-高级教程-实例-方法:07. Java 实例 – instanceOf 关键字用法
ylbtech-Java-Runoob-高级教程-实例-方法:07. Java 实例 – instanceOf 关键字用法 1.返回顶部 1. Java 实例 - instanceof 关键字用法 ...
- Java-Runoob-高级教程-实例-方法:06. Java 实例 – 方法覆盖
ylbtech-Java-Runoob-高级教程-实例-方法:06. Java 实例 – 方法覆盖 1.返回顶部 1. Java 实例 - 方法覆盖 Java 实例 前面章节中我们已经学习了 Jav ...
- Java-Runoob-高级教程-实例-方法:05. Java 实例 – 阶乘
ylbtech-Java-Runoob-高级教程-实例-方法:05. Java 实例 – 阶乘 1.返回顶部 1. Java 实例 - 阶乘 Java 实例 一个正整数的阶乘(英语:factoria ...
- Java-Runoob-高级教程-实例-方法:04. Java 实例 – 斐波那契数列
ylbtech-Java-Runoob-高级教程-实例-方法:04. Java 实例 – 斐波那契数列 1.返回顶部 1. Java 实例 - 斐波那契数列 Java 实例 斐波那契数列指的是这样一 ...
随机推荐
- MySQL-8.0.20
版本: 8.0.20 操作: Centos 7 Linux 未介绍针对数据库的详细操作,如有需求请前往 第一章 MySQL的介绍及安装 1.介绍 1.1 数据库管理系统(DBMS) RDBMS : O ...
- DP(优化)
史不分好坏.是史就应该冲进. 细节见其他题解. P10538 首先建出部分分 sub1 的图,发现是 DAG,于是设点为状态,即即将乘坐 \(j\) 车的最小代价 \(f_j\).这样的转移就是枚举上 ...
- kubesphere应用系列(四)--创建自动流水线
第一步创建多分支流水线 复制生成的url,也可以在编辑设置时复制 第二步新增Jenkinsfile文件 新增Jenkinsfile文件放在根目录 方式一:官方示例:https://github.c ...
- EasyExcel合并行处理并优化
业务场景 由于业务需要导出如下图中订单数据和订单项信息,而一个订单对应多个订单项,所以会涉及到自定义合并行 1.简单处理项目使用的EasyExcel,经查找发现Excel种有个AbstractMerg ...
- Thymeleaf遍历选中多个复选框
使用场景:用户角色一对多关联关系 <!-- roleList:所有角色信息 :userRoleList:用户已有角色id列表--> <input th:each="role ...
- intellij debug模式提示 Method breakpoints may dramatically slow down debugging 解决办法
直接上图........ 点击图中按钮 或者 快捷键(Ctrl - Shift -F8 ) 出现下图
- autMan奥特曼机器人-wxbot邀请入群插件的使用
内置微信(非微信框架)的拉群插件怎么用? 一.安装"wxbot邀请入群"插件 二.在"我的"->"wxbot邀请入群"->配参中 ...
- Vigenere密码无密钥求解
0.前言 最近摸了很长时间的鱼,然后最近突然想搞一个Vigenere密码的自动求解,花了不到一天来实现了一下这个东西,不过受限于自己的水平,没有搞的太难.当然,代码部分不是全部都是从 0 开始的,关于 ...
- Java、Python等接入方式对接股票数据源API接口
为了创建一个Python项目来对接StockTV的API接口,我们可以使用requests库来发送HTTP请求,并使用websocket-client库来处理WebSocket连接.以下是一个简单的P ...
- 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
3月6日最新消息,阿里云通义千问官方宣布推出最新推理模型 QwQ-32B,这一模型仅有 32B 参数,但在效果上与拥有 671B 参数的 DeepSeek-R1 相媲美.如果你自己部署 DeepSee ...