一个例子看 Dart 和 Java 谁快 | Flutter

859 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

前面

首先我们来简单猜测一下
Dart 在 release 下会被打包成 so,也就是运行状态是二进制运行,料想速度应该不会差。
并且很多文章也说 因为 Dart 会 打包成 so,比 打包成 js.bundle 的竟品 React Native 快。
速度 "最快" c 语言的运行产物也是 so,那 so 应该非常快。
毕竟 的,光听声就很 soon

java 产出物是字节码,不是二进制,是运行在虚拟机上的。可能会比较慢,但是又经过这么多年的优化,可能又不会很慢。

那就姑且认为 DartJava 半斤八两吧

以计算 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 快。

image.png

事后再想想

纯粹的 Dart 对比 纯粹 Java 慢4倍多,看来当遇到大型计算时,把计算放到 java 端也是个不错的选择。
但是还没想到 什么 Dart 比 Java 慢这么多,估计需要了解到 Dart 底层 和一些编译原理和操作系统的知识才能知晓。

后面

欲听 Dart 为什么比 Java 慢,10 年之后我们再揭晓,敬请期待。