我看到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: Grand总时间(5次运行):12361毫秒,文件读取总时间:13304毫秒
c#:总时间(5次运行):17504毫秒,文件读取总时间:17956毫秒
三星Galaxy S2 SGH-I777 (Android 4.0.4, API 15) - CyanogenMod ROM
Java: Grand总时间(5次运行):8947 ms,文件读取总时间:9186 ms
c#:总时间(5次运行):9884毫秒,文件读取总时间:10247毫秒
三星GT-N7100 (Android 4.1.1 JellyBean, API 16) -三星ROM
Java: Grand总时间(5次运行):9742毫秒,文件读取总时间:10111毫秒
c#:总时间(5次运行):10459毫秒,文件读取总时间:10696毫秒
模拟器-英特尔(Android 4.2, API 17)
Java:总时间(5次运行):2699毫秒,文件读取总时间:3127毫秒
c#:总时间(5次运行):2049毫秒,文件读取总时间:2182毫秒
模拟器- Intel (Android 2.3.7, API 10)
Java: Grand总时间(5次运行):2992毫秒,文件读取总时间:3591毫秒
c#:总时间(5次运行):2049毫秒,文件读取总时间:2257毫秒
模拟器- Arm (Android 4.0.4, API 15)
Java:总时间(5次运行):41751毫秒,文件读取总时间:43866毫秒
c#:总时间(5次运行):44136毫秒,文件读取总时间:45109毫秒
简短的讨论
我的测试代码主要包含文本解析、替换和Regex搜索,也许对于其他代码(例如更多的数值操作),结果会有所不同。在所有带有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处理器。与Intel HAX模拟器一样,c#在这里运行得更快。以下是我的结果:
Genymotion模拟器- Intel (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: Grand总时间(5次运行):8103 ms,文件读取总时间:8569 ms 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#似乎只是稍微慢了一点,但这些数字让我犹豫了一下:为什么Note 2的处理器更快,但运行时间却比Nook HD+要长?答案是:节电模式。在Nook上,它是禁用的,在Note 2上是启用的。决定在禁用省电模式的情况下测试(与启用省电模式一样,它也会限制处理器的速度):
三星Galaxy Note 2 - ARM (Android 4.1.1),省电禁用
Java: Grand总时间(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 ms,文件读取总时间:587 ms
看起来对于我的特定测试,本机代码比Java快6到7倍。警告:不能在Android上使用std::regex类,所以必须自己编写专门的例程来搜索段落中断或html标签。我最初在PC上使用regex测试相同的代码,比Java快4到5倍。
唷!用char*或wchar*指针再次唤醒原始内存,我立刻感觉自己年轻了20岁!:)
编辑2013年7月15日
(请参见下面,2013年7月30日的编辑,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.
为了比较,我也在ARM设备上运行测试——这里的Dot42代码“仅”比Xamarin c#慢2倍。以下是我的结果:
HTC Nexus One Android 2.3.7 (ARM)
Java: Grand总时间(5次运行):12187毫秒,文件读取总时间:13200毫秒 Xamarin c#:总时间(5次运行):13935毫秒,文件读取总时间:14465毫秒 Dot42 c#:总时间(5次运行):26000 ms,文件读取总时间:27168 ms
三星Galaxy Note 2, Android 4.1.1 (ARM)
Java: Grand总时间(5次运行):6895毫秒,文件读取总时间:7275毫秒 Xamarin c#:总时间(5次运行):6466毫秒,文件读取总时间:6720毫秒 Dot42 c#:总时间(5次运行):11185毫秒,文件读取总时间:11843毫秒
Intel模拟器,Android 4.2 (x86)
Java:总时间(5次运行):2389 ms,文件读取总时间:2770 ms Xamarin c#:总时间(5次运行):1748毫秒,文件读取总时间:1933毫秒 Dot42 c#:总时间(5次运行):5150毫秒,文件读取总时间:5459毫秒
对我来说,同样有趣的是,Xamarin c#在新的ARM设备上比Java略快,而在旧的Nexus One上略慢。如果有人也想运行这些测试,请告诉我,我会在GitHub上更新源代码。如果能看到搭载英特尔处理器的真正Android设备的结果,那将是非常有趣的。
更新7/26/2013
只是一个快速更新,用最新的Xamarin重新编译了基准应用程序。Android 4.8,以及今天发布的dot42 1.0.1.72更新-与之前报告的结果相比没有显著变化。
2013年7月30日更新- dot42更好的结果
重新测试Dot42与罗伯特(从Dot42制造商)的端口我的Java代码到c#。在我最初为Xamarin所做的c#移植中,我用c#原生的List类替换了一些原生Java类,如lisstarray等。Robert没有我的Dot42源代码,所以他再次从Java移植,并在这些地方使用原始的Java类,这对Dot42有利,我猜是因为它运行在Dalvik VM中,像Java,而不是在Mono中,像Xamarin。现在Dot42的结果好多了。以下是我的测试日志:
7/30/2013 - Dot42 tests with more Java classes in Dot42 C# Intel emulator, Android 4.2 Dot42, Greg's Code using StringBuilder.Replace() (as in Xamarin): Grand total time (5 runs): 3646 ms, with file reading total: 3830 ms Dot42, Greg's Code using String.Replace() (as in Java and Robert's code): Grand total time (5 runs): 3027 ms, with file reading total: 3206 ms Dot42, Robert's Code: Grand total time (5 runs): 1781 ms, with file reading total: 1999 ms Xamarin: Grand total time (5 runs): 1373 ms, with file reading total: 1505 ms Java: Grand total time (5 runs): 1841 ms, with file reading total: 2044 ms ARM, Samsung Galaxy Note 2, power saving off, Android 4.1.1 Dot42, Greg's Code using StringBuilder.Replace() (as in Xamarin): Grand total time (5 runs): 10875 ms, with file reading total: 11280 ms Dot42, Greg's Code using String.Replace() (as in Java and Robert's code): Grand total time (5 runs): 9710 ms, with file reading total: 10097 ms Dot42, Robert's Code: Grand total time (5 runs): 6279 ms, with file reading total: 6622 ms Xamarin: Grand total time (5 runs): 6201 ms, with file reading total: 6476 ms Java: Grand total time (5 runs): 7141 ms, with file reading total: 7479 ms
我仍然认为Dot42还有很长的路要走。拥有类似Java的类(例如ArrayList)和良好的性能将使代码从Java移植到c#稍微容易一些。然而,这是我不太可能经常做的事情。我宁愿使用现有的c#代码(库等),这将使用本机c#类(例如List),这将与当前的dot42代码执行缓慢,与Xamarin非常好。
Greg