564

我遇到了 Xamarin 声称他们在 Android 上的 Mono 实现和他们的 C# 编译的应用程序比 Java 代码更快。是否有人在不同的 Android 平台上对非常相似的 Java 和 C# 代码执行实际基准测试以验证此类声明,可以发布代码和结果?

添加于 2013 年 6 月 18 日

由于没有答案,也找不到其他人做过的基准测试,所以决定自己做测试。不幸的是,我的问题仍然“锁定”,所以我不能将此作为答案发布,只能编辑问题。请投票重新打开这个问题。对于 C#,我使用了 Xamarin.Android Ver。4.7.09001(测试版)。源代码,我用于测试和编译 APK 包的所有数据都在 GitHub 上:

Java:https ://github.com/gregko/TtsSetup_Java

C#:https ://github.com/gregko/TtsSetup_C_sharp

如果有人想在其他设备或模拟器上重复我的测试,我也有兴趣了解结果。

我的测试结果

我将我的句子提取器类移植到 C#(来自我的 @Voice Aloud Reader 应用程序),并对 10 个英语、俄语、法语、波兰语和捷克语的 HTML 文件进行了一些测试。每次运行对所有 10 个文件执行 5 次,下面发布了 3 个不同设备和一个模拟器的总时间。我只测试了“发布”版本,没有启用调试。

HTC Nexus One Android 2.3.7 (API 10) - CyanogenMod ROM

Java:总计时间(5 次运行):12361 毫秒,文件读取总计:13304 毫秒

C#:总计时间(5 次运行):17504 毫秒,文件读取总计:17956 毫秒

三星 Galaxy S2 SGH-I777 (Android 4.0.4, API 15) - CyanogenMod ROM

Java:总计时间(5 次运行):8947 毫秒,文件读取总计:9186 毫秒

C#:总计时间(5 次运行):9884 毫秒,文件读取总计:10247 毫秒

三星 GT-N7100 (Android 4.1.1 JellyBean, API 16) - 三星 ROM

Java:总时间(5 次运行):9742 毫秒,文件读取总时间:10111 毫秒

C#:总计时间(5 次运行):10459 毫秒,文件读取总计:10696 毫秒

模拟器 - 英特尔(Android 4.2,API 17)

Java:总时间(5 次运行):2699 毫秒,文件读取总时间:3127 毫秒

C#:总时间(5 次运行):2049 毫秒,文件读取总时间:2182 毫秒

模拟器 - 英特尔(Android 2.3.7,API 10)

Java:总时间(5 次运行):2992 毫秒,文件读取总时间:3591 毫秒

C#:总计时间(5 次运行):2049 毫秒,文件读取总计:2257 毫秒

模拟器 - Arm(Android 4.0.4,API 15)

Java:总时间(5 次运行):41751 毫秒,文件读取总时间:43866 毫秒

C#:总计时间(5 次运行):44136 毫秒,文件读取总计:45109 毫秒

简要讨论

我的测试代码主要包含文本解析、替换和正则表达式搜索,也许对于其他代码(例如更多数字运算)结果会有所不同。在所有配备 ARM 处理器的设备上,Java 的性能优于 Xamarin C# 代码。最大的区别是在 Android 2.3 下,其中 C# 代码的运行速度约为。Java 速度的 70%。

在 Intel 仿真器(采用 Intel HAX 技术,仿真器以快速 virt 模式运行)上,Xamarin C# 代码运行我的示例代码比 Java 快得多 - 大约快 1.35 倍。也许 Mono 虚拟机代码和库在 Intel 上比在 ARM 上优化得更好?

编辑 2013 年 7 月 8 日

我刚刚安装了 Genymotion Android 模拟器,它在 Oracle VirtualBox 中运行,这个模拟器再次使用本机英特尔处理器,而不是模拟 ARM 处理器。与英特尔 HAX 仿真器一样,C# 在这里的运行速度也快得多。这是我的结果:

Genymotion 模拟器 - 英特尔(Android 4.1.1,API 16)

Java:总时间(5 次运行):2069 毫秒,文件读取总时间:2248 毫秒

C#:总计时间(5 次运行):1543 毫秒,文件读取总计:1642 毫秒

然后我注意到 Xamarin.Android beta 版本 4.7.11 有更新,发行说明也提到了 Mono 运行时的一些变化。决定快速测试一些 ARM 设备,并大吃一惊 - C# 数字有所改进:

BN Nook XD+,ARM (Android 4.0)

Java:总时间(5 次运行):8103 毫秒,文件读取总时间:8569 毫秒

C#:总计时间(5 次运行):7951 毫秒,文件读取总计:8161 毫秒

哇!C# 现在比 Java 好?决定在我的 Galaxy Note 2 上重复测试:

三星 Galaxy Note 2 - ARM (Android 4.1.1)

Java:总时间(5 次运行):9675 毫秒,文件读取总时间:10028 毫秒

C#:总计时间(5 次运行):9911 毫秒,文件读取总计:10104 毫秒

这里 C# 似乎只是稍微慢了一点,但这些数字让我停顿了一下:为什么时间比 Nook HD+ 长,即使 Note 2 有更快的处理器?答案:省电模式。在 Nook 上,它被禁用,在 Note 2 上 - 启用。决定在禁用省电模式的情况下进行测试(与启用一样,它也会限制处理器速度):

三星 Galaxy Note 2 - ARM (Android 4.1.1),已禁用省电功能

Java:总时间(5 次运行):7153 毫秒,文件读取总时间:7459 毫秒

C#:总计时间(5 次运行):6906 毫秒,文件读取总计:7070 毫秒

现在,令人惊讶的是,C# 在 ARM 处理器上也比 Java 稍快。大进步!

编辑 2013 年 7 月 12 日

我们都知道,在速度方面没有什么比本机代码更好的了,而且我对我在 Java 或 C# 中的分句器的性能不满意,特别是我需要改进它(因此让它变得更慢)。决定用 C++ 重写它。这是我的 Galaxy Note 2 上的原生速度与 Java 速度的一小部分(即比以前的测试更小的文件集,出于其他原因)比较,其中禁用了省电模式:

Java:总时间(5 次运行):3292 毫秒,文件读取总时间:3454 毫秒

原生拇指:总计时间(5 次运行):537 毫秒,文件读取总计:657 毫秒

本机手臂:总时间(5 次运行):458 毫秒,文件读取总时间:587 毫秒

看起来对于我的特定测试,本机代码比 Java 快 6 到 7 倍。警告:无法在 Android 上使用 std::regex 类,因此必须编写我自己的专门例程来搜索段落中断或 html 标记。我在 PC 上使用正则表达式对相同代码的初始测试比 Java 快了大约 4 到 5 倍。

呸!再次用 char* 或 wchar* 指针唤醒原始内存,我瞬间感觉年轻了 20 岁!:)

编辑 2013 年 7 月 15 日

(请参见下文,编辑于 2013 年 7 月 30 日,以获得更好的 Dot42 效果)

遇到一些困难,我设法将我的 C# 测试移植到 Dot42(版本 1.0.1.71 beta),这是另一个适用于 Android 的 C# 平台。初步结果表明,在英特尔 Android 模拟器上,Dot42 代码比 Xamarin C# (v. 4.7.11) 慢约 3 倍(3 倍)。一个问题是 Dot42 中的 System.Text.RegularExpressions 类没有我在 Xamarin 测试中使用的 Split() 函数,所以我改用 Java.Util.Regex 类和 Java.Util.Regex.Pattern.Split() ,所以在代码的这个特定位置,有这个小的差异。不过应该问题不大。Dot42 编译为 Dalvik (DEX) 代码,因此它原生与 Android 上的 Java 协作,不需要像 Xamarin 那样从 C# 到 Java 的昂贵互操作。

只是为了比较,我还在 ARM 设备上运行测试 - 这里的 Dot42 代码“仅”比 Xamarin C# 慢 2 倍。这是我的结果:

HTC Nexus One 安卓 2.3.7 (ARM)

Java:总计时间(5 次运行):12187 毫秒,文件读取总计:13200 毫秒

Xamarin C#:总计时间(5 次运行):13935 毫秒,文件读取总计:14465 毫秒

Dot42 C#:总时间(5 次运行):26000 毫秒,文件读取总时间:27168 毫秒

三星 Galaxy Note 2,Android 4.1.1 (ARM)

Java:总计时间(5 次运行):6895 毫秒,文件读取总计:7275 毫秒

Xamarin C#:总计时间(5 次运行):6466 毫秒,文件读取总计:6720 毫秒

Dot42 C#:总时间(5 次运行):11185 毫秒,文件读取总时间:11843 毫秒

英特尔仿真器,Android 4.2 (x86)

Java:总时间(5 次运行):2389 毫秒,文件读取总时间:2770 毫秒

Xamarin C#:总计时间(5 次运行):1748 毫秒,文件读取总计:1933 毫秒

Dot42 C#:总时间(5 次运行):5150 毫秒,文件读取总时间:5459 毫秒

对我来说,有趣的是,Xamarin C# 在较新的 ARM 设备上比 Java 稍快,在旧的 Nexus One 上稍慢。如果有人也想运行这些测试,请告诉我,我会更新 GitHub 上的源代码。看到带有英特尔处理器的真正 Android 设备的结果会特别有趣。

2013 年 7 月 26 日更新

只是一个快速更新,由具有最新 Xamarin.Android 4.8 和今天发布的 dot42 1.0.1.72 更新的基准应用程序重新编译 - 与之前报告的结果相比没有显着变化。

2013 年 7 月 30 日更新 - dot42 的结果更好

使用 Robert(来自 dot42 制造商)将我的 Java 代码移植到 C# 重新测试了 Dot42。在最初为 Xamarin 完成的 C# 移植中,我将一些原生 Java 类(如 ListArray)替换为 C# 原生的 List 类等。Robert 没有我的 Dot42 源代码,因此他再次从 Java 移植它并使用原始 Java 类这样的地方,这有利于 Dot42,我猜是因为它在 Dalvik VM 中运行,如 Java,而不是在 Mono 中,如 Xamarin。现在 Dot42 结果好多了。这是我的测试日志:

2013 年 7 月 30 日 - 在 Dot42 C# 中使用更多 Java 类进行 Dot42 测试

英特尔模拟器,Android 4.2

Dot42,使用 StringBuilder.Replace() 的 Greg 代码(如在 Xamarin 中):
总时间(5 次运行):3646 毫秒,文件读取总计:3830 毫秒

Dot42,使用 String.Replace() 的 Greg 的代码(如 Java 和 Robert 的代码):
总时间(5 次运行):3027 毫秒,文件读取总计:3206 毫秒

Dot42,罗伯特的代码:
总时间(5 次运行):1781 毫秒,文件读取总时间:1999 毫秒

Xamarin:
总计时间(5 次运行):1373 毫秒,文件读取总计:1505 毫秒

Java:
总计时间(5 次运行):1841 毫秒,文件读取总计:2044 毫秒

ARM、三星 Galaxy Note 2、省电关闭、Android 4.1.1

Dot42,使用 StringBuilder.Replace() 的 Greg 代码(如在 Xamarin 中):
总时间(5 次运行):10875 毫秒,文件读取总计:11280 毫秒

Dot42,使用 String.Replace() 的 Greg 的代码(如 Java 和 Robert 的代码):
总时间(5 次运行):9710 毫秒,文件读取总计:10097 毫秒

Dot42,罗伯特的代码:
总时间(5 次运行):6279 毫秒,文件读取总时间:6622 毫秒

Xamarin:
总计时间(5 次运行):6201 毫秒,文件读取总计:6476 毫秒

Java:
总计时间(5 次运行):7141 毫秒,文件读取总计:7479 毫秒

我仍然认为Dot42还有很长的路要走。拥有类似 Java 的类(例如 ArrayList)和良好的性能将使从 Java 到 C# 的代码移植稍微容易一些。然而,这是我不太可能做的事情。我宁愿使用现有的 C# 代码(库等),它将使用本机 C# 类(例如 List),并且在当前的 dot42 代码中运行缓慢,并且在 Xamarin 中运行良好。

格雷格

4

7 回答 7

65

是的,Xamarin 的 Mono 虚拟机比 Android 中使用的 Google 的 Dalvik 更令人印象深刻。我已经使用 HTC Flyer 和 Acer Iconia Tab 平板电脑对其进行了测试,以通过 Mono 与 Java Dalvik 对 Android 的 C# 端口进行基准测试,Android 的 C# 实现很好,并且真正击败了基于 Java 的 Dalvik。

于 2013-06-16T15:50:39.263 回答
44
I came across this interesting post

https://medium.com/@harrycheung/mobile-app-performance-redux-e512be94f976#.kfbauchtz

Android 应用性能

iOS 应用性能

希望这些信息有所帮助。

于 2016-04-22T09:00:35.830 回答
34

我们最近调查了将 Xamarin 用于应用程序的情况。我们使用了已经为我们的应用程序的 Windows RT 版本编写的 C# 代码。必须为 Android 版本重写一些具体细节。

我们发现 Xamarin C# 中的 I/O 比 Java 慢大约 2 倍。我们的应用程序受大量 I/O 限制。我们还没有发现这个问题的原因,但目前我们假设它是由于编组造成的。虽然我们大部分时间都尝试留在 Mono VM 中,但我们不知道 Mono 实际如何访问磁盘。

这也说明我们的 C# 代码使用 SQLite.NET ( https://github.com/praeclarum/sqlite-net )。使用 SQLite.NET 代码进行相同的提取也比使用 Android 的 Java SQLite 包装器慢 2 倍。看了源码,好像是直接绑定到C.dll上的,不知道为什么这么慢。一种可能性是,在 Android 上将字符串从原生到 Java 的封送处理可能比在 Xamarin 上从原生到 C# 更快。

于 2014-06-05T15:30:19.117 回答
33

这是我想与您分享的另一篇更新的博客文章。他将 Xamarin 与 IO 和 Android 上的本机代码和 Cordova 进行了比较。

简而言之,Xamarin 有时比本机代码执行得更好。他测试了应用程序的大小、加载时间、从 Azure 服务加载列表和素数计算。

享受!

编辑:我更新了死链接,我注意到有第 2 部分

于 2015-02-25T09:17:44.980 回答
11

以下是我在以下两个设备上的本机、Xamarin 和 Xamarin.Forms 解决方案(测试还包括 iOS 性能)之间的另一项测试中发现的一些信息:

三星 Galaxy A7:Android 操作系统版本:6.0 中央处理器:八核 1.9 GHz Cortex-A53 内存:3GB 显示分辨率:1920×1080

iPhone 6s:iOS 版本:10.3.3 中央处理器:双核 1.84 GHz Twister RAM:2 GB 显示分辨率:1334×750

比较了一些常见的功能,每一个都有自己的应用程序:

- Basic “Hello World”
- REST API
- JSON Serialization/Deserialization
- Photo Loading
- SQL Database Insert and Get All

每个测试重复多次,图表显示平均结果。


你好世界

基本的 Hellow World 性能比较


休息 API

一组测试旨在测量应用程序使用 OpenWeatherMap API 通过 REST API 发送请求并在不进行进一步数据处理的情况下接收响应所需的时间。

Rest API 性能对比


JSON 操作 测试使用 Newtonsoft Json.net 框架对所有 Xamarin 应用程序中的 JSON 对象进行序列化和反序列化。本机 Android 序列化和反序列化使用两个 Java 库进行测试:Jackson 和 GSON。

进行了两次运行,第一次从头开始,第二次使用缓存的信息和操作

第一次运行 :

JSON序列化首次运行

JSON反序列化首次运行

(本机 iOS JSON 操作正在扼杀这个测试,Xamarin 在第二个加入它)

JSON序列化第二次运行

JSON反序列化第二次运行


照片操作

首先加载具有三种不同分辨率的图像:

Resolution – 858×569, Size – 868Kb
Resolution – 2575×1709, Size – 8Mb
Resolution – 4291×2848, Size – 28.9Mb

图像首先加载 Android

图像首先加载 iOS

此测试的 Xamarin.Forms 结果似乎有些不确定,因此未包含在图表中。


SQLite 操作

测试了两个操作:

BulkInsert: Loading rows of data into a database table.
GetAll: Retrieving all data from the database.

数据库有 10,000 条记录。所有操作都在设备内部处理。

SQLite Android 性能

SQLite iOS 性能


Xamarin Native (Xamarin.iOS/Xamarin.Android) 显示自己是本机代码的相当不错的替代品,而 Xamarin.Forms 在很多情况下似乎很慢,但它可以是快速开发非常简单的应用程序的一个非常好的解决方案。

完整的测试来自这个来源:

https://www.altexsoft.com/blog/engineering/performance-comparison-xamarin-forms-xamarin-ios-xamarin-android-vs-android-and-ios-native-applications/

感谢您给我解释以增强我的答案,希望这会有所帮助:)

于 2017-11-02T09:49:54.403 回答
7

表现

如果您没有定义性能的含义,性能是一个模糊的词,如果它是简单的计算性能,Xamarin 可以比 Java 更快,具体取决于计算的性质。

Android 自带多种形式来执行代码:

  • 渲染脚本(CPU 和 GPU)
  • Java (SDK)
  • C++ (NDK)
  • OpenGL(图形处理器)

很明显,当执行代码时,解决方案越原生,它就会越快。基于运行时的语言永远不会击败直接在 CPU 上运行的语言。

但另一方面,如果你想衡量实际使用性能,Java 肯定会比 Xamarin 更快。

Xamarin 以及为什么它会变慢

将 Xamarin 与普通的旧 Java 应用程序进行比较时,Xamarin 的性能可能会更快,因为它可能会更慢。

在实际示例中,Xamarin 应用程序很可能比 Java 应用程序慢,因为需要使用所谓的绑定将许多 Android/Java(系统)调用委托给 Xamarin 运行时和从 Xamarin 运行时委托。

了解几种不同类型的绑定很重要:

  • JNI(Java Native Interface):在许多安卓应用程序中使用的绑定Java代码(SDK)和本地C++代码(NDK)之间的接口。
  • MCW(托管可调用包装器): Xamarin 中提供的一种绑定,用于从托管 C# 代码到 Java 代码(Android 运行时)的接口。
  • ACW(Android 可调用包装器): Xamarin 中可用的绑定,用于从 Java 代码(Android 运行时)接口到托管 C# 代码。

更多关于 MCW 和 ACW 的信息:https ://developer.xamarin.com/guides/cross-platform/application_fundamentals/building_cross_platform_applications/part_1_-_understanding_the_xamarin_mobile_platform/

绑定在性能方面非常非常昂贵。从 Java 调用 C++ 方法会增加调用时间的巨大开销,从 C++ 中调用 C++ 方法要快很多很多倍。

有人做了一个性能测试,计算了一个 JNI 调用平均需要多少 Java 操作:进行 JNI 调用的量化开销是多少?

但不仅 JNI 调用成本高昂,与 MCW 和 ACW 之间的调用也是如此。现实世界的 Xamarin 应用程序使用绑定进行许多调用,并且由于这种现实世界的 Xamarin 应用程序的使用可能(并且通常会)比普通的旧 Java 应用程序慢。但是,根据 Xamarin 应用程序的设计方式,用户很可能甚至不会注意到差异。

TLDR/结论: Xamarin 需要使用各种绑定,这很耗时。

除了绑定之外,在谈论实际性能时还涉及许多其他因素,例如:二进制文件的大小、在内存中加载应用程序、I/O 操作等等。可以在此处找到调查其中一些内容的博客文章:https ://magenic.com/thinking/mobile-development-platform-performance-part-2-native-cordova-classic-xamarin-xamarin-forms

于 2017-10-27T11:18:14.703 回答
3

这是相当古老的测试,但可能是相关的:https ://github.com/EgorBo/Xamarin.Android-vs-Java

算术测试

在此处输入图像描述

集合、泛型、自定义值类型

在此处输入图像描述

使用字符串

在此处输入图像描述

UPD: Google Pixel 2 的新数据(感谢yousha-aleayoub

Pixel 2 测试

于 2017-10-27T05:19:59.430 回答