开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情
前面
首先我们来简单猜测一下
Dart 在 release 下会被打包成 so,也就是运行状态是二进制运行,料想速度应该不会差。
并且很多文章也说 因为 Dart 会 打包成 so,比 打包成 js.bundle 的竟品 React Native 快。
速度 "最快" c 语言的运行产物也是 so,那 so 应该非常快。
毕竟 嗖 嗖 嗖 的,光听声就很 soon。
而 java 产出物是字节码,不是二进制,是运行在虚拟机上的。可能会比较慢,但是又经过这么多年的优化,可能又不会很慢。
那就姑且认为 Dart 和 Java 半斤八两吧
以计算 MD5 值为例
实际场景中 需要用到大量计算的,计算 MD5 算是一个。 Android 中更新 apk,下载文件,都需要和服务器对比下 MD5 值是否相同,相同才认为是同一个。
这里先以 100M 的 apk 为例 进行测试
Dart 的速度到底 soon 不?
Digest digest = md5.convert(file.readAsBytesSync().toList());
运行下 耗时 2435 毫秒
Java 的速度 炸不炸
(其实是 Kotlin,姑且当作是 Java 吧)
val md = MessageDigest.getInstance("MD5")
var digest = md.digest(file.readBytes());
val hexString = StringBuilder()
for (aMessageDigest in digest) {
var h = Integer.toHexString(0xFF and aMessageDigest.toInt())
while (h.length < 2) h = "0$h"
hexString.append(h)
}
运行下 耗时 285 毫秒
这么看 Java 的速度是有点 炸。
事后想想
基于浅薄的对于计算机的理解,可能是 使用 Java 自带的 MessageDigest使用了 GPU 进行了运算,所以很快。那能不能用纯 java 实现一遍呢
很纯粹的 Java
为了方便阅读,我把 MD5 的算法全放上来了,算法来自 rosettacode.org/wiki/MD5/Im… 推荐下这个 罗赛塔,编程语言爱好者可以在上面看到相同任务在不同语言上的实现。 code.juejin.cn/api/raw/716…
public class MD5
{
private static final int INIT_A = 0x67452301;
private static final int INIT_B = (int)0xEFCDAB89L;
private static final int INIT_C = (int)0x98BADCFEL;
private static final int INIT_D = 0x10325476;
private static final int[] SHIFT_AMTS = {
7, 12, 17, 22,
5, 9, 14, 20,
4, 11, 16, 23,
6, 10, 15, 21
};
private static final int[] TABLE_T = new int[64];
static
{
for (int i = 0; i < 64; i++)
TABLE_T[i] = (int)(long)((1L << 32) * Math.abs(Math.sin(i + 1)));
}
public static byte[] computeMD5(byte[] message)
{
int messageLenBytes = message.length;
int numBlocks = ((messageLenBytes + 8) >>> 6) + 1;
int totalLen = numBlocks << 6;
byte[] paddingBytes = new byte[totalLen - messageLenBytes];
paddingBytes[0] = (byte)0x80;
long messageLenBits = (long)messageLenBytes << 3;
for (int i = 0; i < 8; i++)
{
paddingBytes[paddingBytes.length - 8 + i] = (byte)messageLenBits;
messageLenBits >>>= 8;
}
int a = INIT_A;
int b = INIT_B;
int c = INIT_C;
int d = INIT_D;
int[] buffer = new int[16];
for (int i = 0; i < numBlocks; i ++)
{
int index = i << 6;
for (int j = 0; j < 64; j++, index++)
buffer[j >>> 2] = ((int)((index < messageLenBytes) ? message[index] : paddingBytes[index - messageLenBytes]) << 24) | (buffer[j >>> 2] >>> 8);
int originalA = a;
int originalB = b;
int originalC = c;
int originalD = d;
for (int j = 0; j < 64; j++)
{
int div16 = j >>> 4;
int f = 0;
int bufferIndex = j;
switch (div16)
{
case 0:
f = (b & c) | (~b & d);
break;
case 1:
f = (b & d) | (c & ~d);
bufferIndex = (bufferIndex * 5 + 1) & 0x0F;
break;
case 2:
f = b ^ c ^ d;
bufferIndex = (bufferIndex * 3 + 5) & 0x0F;
break;
case 3:
f = c ^ (b | ~d);
bufferIndex = (bufferIndex * 7) & 0x0F;
break;
}
int temp = b + Integer.rotateLeft(a + f + buffer[bufferIndex] + TABLE_T[j], SHIFT_AMTS[(div16 << 2) | (j & 3)]);
a = d;
d = c;
c = b;
b = temp;
}
a += originalA;
b += originalB;
c += originalC;
d += originalD;
}
byte[] md5 = new byte[16];
int count = 0;
for (int i = 0; i < 4; i++)
{
int n = (i == 0) ? a : ((i == 1) ? b : ((i == 2) ? c : d));
for (int j = 0; j < 4; j++)
{
md5[count++] = (byte)n;
n >>>= 8;
}
}
return md5;
}
public static String toHexString(byte[] b)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < b.length; i++)
{
sb.append(String.format("%02X", b[i] & 0xFF));
}
return sb.toString();
}
然后再运行,得到 438毫秒,还是比 Dart 快 4 倍多。 看来在密集计算上就是 Java 比 Dart 快。
事后再想想
纯粹的 Dart 对比 纯粹 Java 慢4倍多,看来当遇到大型计算时,把计算放到 java 端也是个不错的选择。
但是还没想到 什么 Dart 比 Java 慢这么多,估计需要了解到 Dart 底层 和一些编译原理和操作系统的知识才能知晓。
后面
欲听 Dart 为什么比 Java 慢,10 年之后我们再揭晓,敬请期待。