问题描述
我发现 Xamarin 声称他们在 Android 上的 Mono 实现和他们的 C# 编译应用程序比 Java 代码更快.有没有人在不同的 Android 平台上对非常相似的 Java 和 C# 代码执行实际基准测试以验证此类声明,可以发布代码和结果吗?
于 2013 年 6 月 18 日添加
由于没有答案,也找不到其他人做过的此类基准测试,所以决定自己做测试.不幸的是,我的问题仍然锁定",因此我无法将此作为答案发布,只能编辑问题.请投票重新打开这个问题.对于 C#,我使用了 Xamarin.Android 版本.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%.
在英特尔模拟器(采用英特尔 HAX 技术,模拟器在快速虚拟模式下运行)上,Xamarin C# 代码运行我的示例代码的速度比 Java 快得多 - 大约快 1.35 倍.也许 Mono 虚拟机代码和库在 Intel 上比在 ARM 上优化得更好?
编辑 2013 年 7 月 8 日
我刚刚安装了 Genymotion Android 模拟器,它在 Oracle VirtualBox 中运行,并且这个模拟器再次使用原生 Intel 处理器,而不是模拟 ARM 处理器.与英特尔 HAX 仿真器一样,C# 再次在这里运行得更快.这是我的结果:
Genymotion 模拟器 - 英特尔(Android 4.1.1,API 16)
Java:总计时间(5 次运行):2069 毫秒,文件读取总计:2248 毫秒
C#:总计时间(5 次运行):1543 毫秒,文件读取总计:1642 毫秒
然后我注意到 Xamarin.Android 测试版有一个更新,版本 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 上 - 启用.决定在禁用省电模式的情况下进行测试(与启用一样,它也会限制处理器速度):
Samsung 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#(版本 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 Android 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# 移植中,我用 C# 原生的 List 类替换了一些原生 Java 类,如 ListArray,等等.Robert 没有我的 Dot42 源代码,所以他再次从 Java 移植它并在这样的地方,有利于 Dot42,我猜是因为它在 Dalvik VM 中运行,如 Java,而不是在 Mono 中,如 Xamarin.现在 Dot42 的结果要好得多.这是我测试的日志:
7/30/2013 - Dot42 在 Dot42 C# 中使用更多 Java 类进行测试
英特尔模拟器,Android 4.2
Dot42,Greg 使用 StringBuilder.Replace() 的代码(如在 Xamarin 中):
总计时间(5 次运行):3646 毫秒,文件读取总计:3830 毫秒
Dot42,Greg 使用 String.Replace() 的代码(如 Java 和 Robert 的代码):
总计时间(5 次运行):3027 毫秒,文件读取总计:3206 毫秒
Dot42,罗伯特的代码:
总计时间(5 次运行):1781 毫秒,文件读取总计:1999 毫秒
Xamarin:
总计时间(5 次运行):1373 毫秒,文件读取总计:1505 毫秒
Java:
总计时间(5 次运行):1841 毫秒,文件读取总计:2044 毫秒
ARM,Samsung Galaxy Note 2,省电关闭,Android 4.1.1
Dot42,Greg 使用 StringBuilder.Replace() 的代码(如在 Xamarin 中):
总计时间(5 次运行):10875 毫秒,文件读取总计:11280 毫秒
Dot42,Greg 使用 String.Replace() 的代码(如 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 时效果很好.
格雷格
是的,Xamarin 的 Mono 虚拟机比 Android 中使用的 Google 的 Dalvik 更令人印象深刻.我已经用 HTC Flyer 和 Acer Iconia Tab 平板电脑对其进行了测试,通过 Mono 对 Android 的 C# 端口与 Java Dalvik 进行了基准测试,Android 的 C# 实现很好,真正击败了基于 Java 的 Dalvik.
I came across Xamarin claims that their Mono implementation on Android and their C# compiled apps are faster than Java code. Did anyone perform actual benchmarks on very similar Java and C# code on different Android platforms to verify such claims, could post the code and results?
Added June 18, 2013
Since there was no answer and could not find such benchmarks done by others, decided to do my own tests. Unfortunately, my question remains "locked" so I cannot post this as the answer, only edit the question. Please vote to re-open this question. For C#, I used Xamarin.Android Ver. 4.7.09001 (beta). The source code, all the data I used for testing and compiled APK packages are on GitHub:
Java: https://github.com/gregko/TtsSetup_Java
C#: https://github.com/gregko/TtsSetup_C_sharp
If someone would like to repeat my tests on other devices or emulators, I'd be interested to learn the results as well.
Results from my testing
I ported my sentence extractor class to C# (from my @Voice Aloud Reader app) and run some tests on 10 HTML files in English, Russian, French, Polish and Czech languages. Each run was performed 5 times on all 10 files, and the total time for 3 different devices and one emulator are posted below. I tested "Release" builds only, without debugging enabled.
HTC Nexus One Android 2.3.7 (API 10) - CyanogenMod ROM
Java: Grand total time (5 runs): 12361 ms, with file reading total: 13304 ms
C#: Grand total time (5 runs): 17504 ms, with file reading total: 17956 ms
Samsung Galaxy S2 SGH-I777 (Android 4.0.4, API 15) - CyanogenMod ROM
Java: Grand total time (5 runs): 8947 ms, with file reading total: 9186 ms
C#: Grand total time (5 runs): 9884 ms, with file reading total: 10247 ms
Samsung GT-N7100 (Android 4.1.1 JellyBean, API 16) - Samsung ROM
Java: Grand total time (5 runs): 9742 ms, with file reading total: 10111 ms
C#: Grand total time (5 runs): 10459 ms, with file reading total: 10696 ms
Emulator - Intel (Android 4.2, API 17)
Java: Grand total time (5 runs): 2699 ms, with file reading total: 3127 ms
C#: Grand total time (5 runs): 2049 ms, with file reading total: 2182 ms
Emulator - Intel (Android 2.3.7, API 10)
Java: Grand total time (5 runs): 2992 ms, with file reading total: 3591 ms
C#: Grand total time (5 runs): 2049 ms, with file reading total: 2257 ms
Emulator - Arm (Android 4.0.4, API 15)
Java: Grand total time (5 runs): 41751 ms, with file reading total: 43866 ms
C#: Grand total time (5 runs): 44136 ms, with file reading total: 45109 ms
Brief discussion
My test code contains mainly text parsing, replacing and Regex searches, perhaps for other code (e.g. more numeric operations) the results would be different. On all devices with ARM processors, Java performed better than Xamarin C# code. The largest difference was under Android 2.3, where C# code run at approx. 70% of Java speed.
On Intel emulator (with Intel HAX technology, emulator runs in fast virt mode), Xamarin C# code runs my sample code much faster than Java - about 1.35 time faster. Maybe Mono virtual machine code and libraries are much better optimized on Intel than on ARM?
Edit July 8, 2013
I just installed Genymotion Android emulator, which runs in Oracle VirtualBox, and again this one uses native Intel processor, not emulating ARM processor. As with Intel HAX emulator, again C# runs here much faster. Here are my results:
Genymotion emulator - Intel (Android 4.1.1, API 16)
I then noticed that there was an update to Xamarin.Android beta, version 4.7.11, with release notes mentioning some changes in Mono runtime as well. Decided to quickly test some ARM devices, and big surprise - C# numbers improved:
BN Nook XD+, ARM (Android 4.0)
Wow! C# is now better than Java? Decided to repeat the test on my Galaxy Note 2:
Samsung Galaxy Note 2 - ARM (Android 4.1.1)
Here C# seems to be only slightly slower, but these numbers gave me a pause: Why the time is longer than on Nook HD+, even though Note 2 has a faster processor? The answer: power saving mode. On Nook, it was disabled, on Note 2 - enabled. Decided to test with power saving mode disabled (as with enabled, it also limits the processor speed):
Samsung Galaxy Note 2 - ARM (Android 4.1.1), power saving disabled
Now, surprisingly, C# is slightly faster than Java on ARM processor as well. Big improvement!
Edit July 12, 2013
We all know, that nothing beats native code for speed, and I was not satisfied with the performance of my sentence splitter in Java or C#, particularly that I need to improve it (and thus make it even slower). Decided to re-write it in C++. Here is a small (i.e. a smaller set of files than previous tests, for other reasons) comparison of the speed of native vs. Java on my Galaxy Note 2, with power saving mode disabled:
Java:Grand total time (5 runs): 3292 ms, with file reading total: 3454 ms
Native thumb:Grand total time (5 runs): 537 ms, with file reading total: 657 ms
Native arm:Grand total time (5 runs): 458 ms, with file reading total: 587 ms
Looks like for my particular test, the native code is 6 to 7 times faster than Java. Caveat: could not use std::regex class on Android, so had to write my own specialized routines searching for paragraphs breaks or html tags. My initial tests of the same code on a PC using regex, were about 4 to 5 times faster than Java.
Phew! Waking raw memory with char* or wchar* pointers again, I instantly felt 20 years younger! :)
Edit July 15, 2013
(Please see below, with edits of 7/30/2013, for much better results with Dot42)
With some difficulty, I managed to port my C# tests to Dot42 (version 1.0.1.71 beta), another C# platform for Android. Preliminary results show that Dot42 code is about 3x (3 times) slower than Xamarin C# (v. 4.7.11), on an Intel Android emulator. One problem is that System.Text.RegularExpressions class in Dot42 does not have the Split() function that I used in Xamarin tests, so I used Java.Util.Regex class instead, and Java.Util.Regex.Pattern.Split(), so in this particular place in the code, there is this small difference. Should not be a big problem though. Dot42 compiles to Dalvik (DEX) code, so it cooperates with Java on Android natively, does not need expensive interop from C# to Java like Xamarin.
Just for comparison, I also run the test on ARM devices - here the Dot42 code is "only" 2x slower than Xamarin C#. Here are my results:
HTC Nexus One Android 2.3.7 (ARM)
Samsung Galaxy Note 2, Android 4.1.1 (ARM)
Intel emulator, Android 4.2 (x86)
To me, it was also interesting to note that Xamarin C# is slightly faster than Java on a newer ARM device and slightly slower on the old Nexus One. If anyone would like to run these tests as well, please let me know and I'll update the sources on GitHub. It would be particularly interesting to see results from a real Android device with Intel processor.
Update 7/26/2013
Just a quick update, re-compiled by benchmark apps with the latest Xamarin.Android 4.8, and also with dot42 1.0.1.72 update released today - no significant changes from the results reported before.
Update 7/30/2013 - better results for dot42
Re-tested Dot42 with Robert's (from dot42 makers) port of my Java code to C#. In my C# port done initially for Xamarin, I replaced some native Java classes, like ListArray, with List class native to C#, etc. Robert did not have my Dot42 source code, so he ported it again from Java and used original Java classes in such places, which benefits Dot42, I guess because it runs in Dalvik VM, like Java, and not in Mono, like Xamarin. Now Dot42 results are much better. Here is a log from my testing:
I still think that Dot42 has a long way to go. Having Java-like classes (e.g. ArrayList) and a good performance with them would make porting code from Java to C# slightly easier. However, this is something I would not be likely to do a lot. I would rather want to use existing C# code (libraries etc.), which will use native C# classes (e.g. List), and that would perform slowly with the current dot42 code, and very well with Xamarin.
Greg
Yeah, Xamarin's Mono virtual machine is more impressive than Google's Dalvik used in Android. I have tested it with HTC Flyer and Acer Iconia Tab tablets to benchmark the C# port of Android through Mono against Java Dalvik, with the C# implementation of Android well and truly trouncing the Java-based Dalvik.
这篇关于有没有人有比较用 Xamarin C# 和 Java 编写的 Android 应用程序的性能的基准(代码和结果)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!