我偶然发现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种不同设备和1个模拟器的总时间。我仅测试了“发布”版本,而未启用调试。
HTC Nexus One Android 2.3.7(API 10)-CyanogenMod ROM
Java:总计时间(5次运行):12361 ms,文件读取总计:13304 ms
C#:总计总时间(5次运行):17504毫秒,文件读取总计:17956毫秒
三星Galaxy S2 SGH-I777(Android 4.0.4,API 15)-CyanogenMod ROM
Java:总计时间(5次运行):8947 ms,文件读取总计:9186 ms
C#:总计总时间(5次运行):9884 ms,文件读取总计:10247 ms
三星GT-N7100(Android 4.1.1 JellyBean,API 16)-三星ROM
Java:总计时间(5次运行):9742 ms,文件读取总计:10111 ms
C#:总计总时间(5次运行):10459 ms,文件读取总计:10696 ms
模拟器-英特尔(Android 4.2,API 17)
Java:总计时间(5次运行):2699 ms,文件读取总计:3127 ms
C#:总计时间(5次运行):2049 ms,文件读取总计:2182 ms
模拟器-英特尔(Android 2.3.7,API 10)
Java:总计时间(5次运行):2992 ms,文件读取总计:3591 ms
C#:总计总时间(5次运行):2049 ms,文件读取总时间:2257 ms
模拟器-Arm(Android 4.0.4,API 15)
Java:总计时间(5次运行):41751 ms,文件读取总计:43866 ms
C#:总计总时间(5次运行):44136毫秒,文件读取总计:45109毫秒
简短讨论
我的测试代码主要包含文本解析,替换和Regex搜索,也许对于其他代码(例如更多的数字运算),结果将有所不同。在所有装有ARM处理器的设备上,Java的性能均优于Xamarin C#代码。最大的区别是在Android 2.3下,其中C#代码的运行速度大约为2。Java速度的70%。
在英特尔仿真器(采用英特尔HAX技术,仿真器以快速virt模式运行)上,Xamarin C#代码运行示例代码的速度比Java快得多-大约快1.35倍。也许Mono的虚拟机代码和库在Intel上比在ARM上优化得更好?
编辑2013年7月8日
我刚刚安装了Genymotion Android模拟器,该模拟器在Oracle VirtualBox中运行,并且再次使用本地Intel处理器,而不是ARM处理器。与Intel HAX模拟器一样,C#在这里的运行速度也更快。这是我的结果:
Genymotion模拟器-英特尔(Android 4.1.1,API 16)
Java:总计时间(5次运行):2069 ms,文件读取总计:2248 ms
C#:总计总时间(5次运行):1543毫秒,文件读取总计:1642毫秒
然后,我注意到Xamarin.Android beta 4.7.11版进行了更新,发行说明还提到了Mono运行时中的一些更改。决定快速测试某些ARM设备,并且大吃一惊-C#数量有所改善:
BN Nook XD +,ARM(Android 4.0)
Java:总计时间(5次运行):8103 ms,文件读取总计:8569 ms
C#:总计总时间(5次运行):7951 ms,文件读取总计:8161 ms
哇!C#现在比Java好吗?决定在我的Galaxy Note 2上重复测试:
三星Galaxy Note 2-ARM(Android 4.1.1)
Java:总计时间(5次运行):9675 ms,文件读取总计:10028 ms
C#:总计总时间(5次运行):9911 ms,文件读取总计:10104 ms
这里的C#似乎只是稍微慢一点,但是这些数字让我停了下来:为什么时间比Nook HD +还要长,尽管Note 2的处理器更快?答案:省电模式。在Nook上,它已禁用,在注释2上已启用。决定在禁用节能模式的情况下进行测试(与启用一样,它也限制了处理器速度):
Samsung Galaxy Note 2-ARM(Android 4.1.1),已禁用节能功能
Java:总计时间(5次运行):7153 ms,文件读取总计:7459 ms
C#:总计总时间(5次运行):6906毫秒,文件读取总计:7070毫秒
现在,令人惊讶的是,在ARM处理器上,C#也比Java快一点。大进步!
编辑2013年7月12日
我们都知道,没有什么能比本地代码更好地提高速度了,我对我的Java或C#语句分割器的性能不满意,特别是我需要对其进行改进(使其变得更慢)。决定用C ++重写它。这是我的Galaxy Note 2上本机与Java速度比较小的结果(出于其他原因,文件集比以前的测试要小),并且禁用了省电模式:
Java:总计时间(5次运行):3292 ms,文件读取总计:3454 ms
本地拇指:总计总时间(5次运行):537毫秒,文件读取总计:657毫秒
本机臂:总计总时间(5次运行):458毫秒,文件读取总计:587毫秒
看起来对于我的特定测试,本机代码比Java快6至7倍。警告:无法在Android上使用std :: regex类,因此不得不编写自己的专用例程来搜索段落分隔符或html标签。我在使用regex的PC上对相同代码进行的初始测试大约比Java快4至5倍。
!再次用char *或wchar *指针唤醒原始内存,我立即感到年轻了20岁!:)
编辑2013年7月15日
(请参阅下面的内容,并于2013年7月30日进行了修改,使用Dot42可获得更好的效果)
遇到了一些困难,我设法将C#测试移植到另一个适用于Android的C#平台Dot42(版本1.0.1.71 beta)。初步结果显示,在Intel 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 Android 2.3.7(ARM)
Java:总计时间(5次运行):12187 ms,文件读取总计:13200 ms
Xamarin C#:总计时间(5次运行):13935 ms,文件读取总计:14465 ms
Dot42 C#:总计时间(5次运行):26000 ms,文件读取总计:27168 ms
三星Galaxy Note 2,Android 4.1.1(ARM)
Java:总计时间(5次运行):6895 ms,文件读取总计:7275 ms
Xamarin C#:总计时间(5次运行):6466 ms,文件读取总计:6720 ms
Dot42 C#:总计时间(5次运行):11185 ms,文件读取总计:11843 ms
英特尔模拟器,Android 4.2(x86)
Java:总计时间(5次运行):2389 ms,文件读取总计:2770 ms
Xamarin C#:总计时间(5次运行):1748 ms,文件读取总计:1933 ms
Dot42 C#:总计时间(5次运行):5150 ms,文件读取总计:5459 ms
对我来说,有趣的是,Xamarin C#在较新的ARM设备上比Java快,而在旧的Nexus One上稍慢。如果有人也想运行这些测试,请告诉我,我将在GitHub上更新源代码。看到具有英特尔处理器的真实Android设备的结果将特别有趣。
更新7/26/2013
只是一个快速更新,由基准应用重新编译为最新的Xamarin.Android 4.8,并且今天发布了dot42 1.0.1.72更新-与以前报告的结果相比,没有重大变化。
更新7/30/2013-dot42的更好结果
使用我的Java代码的Robert(来自dot42制造商)端口重新测试了Dot42,并将其移植到C#中。在最初为Xamarin完成的C#端口中,我将某些本地Java类(如ListArray)替换为C#本机的List类,等等。Robert没有我的Dot42源代码,因此他再次从Java移植了它,并在其中使用了原始Java类。这样的地方,对Dot42有利,我想是因为它在Java等Dalvik VM中运行,而不在Xamarin等Mono中运行。现在,Dot42的结果要好得多。这是我测试的日志:
7/30/2013-Dot42在Dot42 C#中使用更多Java类进行测试
英特尔模拟器,Android 4.2
Dot42,使用StringBuilder.Replace()的Greg代码(如Xamarin):
总计时间(5次运行):3646 ms,文件读取总计:3830 msDot42,使用String.Replace()的Greg代码(如Java和Robert的代码):
总计(5次运行)总时间:3027 ms,文件读取总时间:3206 msDot42,罗伯特的代码:
总计时间(5次运行):1781 ms,文件读取总计:1999 msXamarin:
总计时间(5次运行):1373毫秒,文件读取总计:1505毫秒Java:
总计时间(5次运行):1841毫秒,文件读取总计:2044毫秒ARM,三星Galaxy Note 2,省电功能,Android 4.1.1
Dot42,Greg使用StringBuilder.Replace()的代码(如Xamarin):
总计时间(5次运行):10875 ms,文件读取总计:11280 msDot42,使用String.Replace()的Greg代码(如Java和Robert的代码):
总计(5次运行)总时间:9710 ms,文件读取总时间:10097 msDot42,罗伯特的代码:
总计时间(5次运行):6279 ms,文件读取总计:6622 msXamarin:
总计时间(5次运行):6201 ms,文件读取总时间:6476 msJava:
总计时间(5次运行):7141 ms,文件读取总计:7479 ms
我仍然认为Dot42还有很长的路要走。拥有类似Java的类(例如ArrayList)并具有良好的性能将使从Java到C#的代码移植更加容易。但是,这是我不太可能做的事情。我宁愿使用现有的C#代码(库等),这些代码将使用本机C#类(例如List),并且使用当前的dot42代码执行起来会很慢,对于Xamarin来说效果很好。
格雷格