我看到Xamarin声称他们在Android上的Mono实现和c#编译的应用程序比Java代码更快。有没有人在不同的Android平台上对非常相似的Java和c#代码执行实际的基准测试来验证这种说法,可以发布代码和结果?
因为没有答案,也找不到别人做的基准测试,所以我决定自己做测试。不幸的是,我的问题仍然“锁定”,所以我不能把这个作为答案,只能编辑问题。请投票重新讨论这个问题。对于c#,我使用Xamarin。Android Ver. 4.7.09001(测试版)。源代码,我用于测试和编译APK包的所有数据都在GitHub上:
Java: # EYZ0
c#: # EYZ0
如果有人想在其他设备或模拟器上重复我的测试,我也有兴趣了解结果。
我将我的句子提取器类移植到c#(从我的@Voice Aloud Reader应用程序),并在英语、俄语、法语、波兰语和捷克语的10个HTML文件上运行了一些测试。每次运行对所有10个文件执行5次,3个不同设备和一个模拟器的总时间如下所示。我只测试了“发布”版本,没有启用调试。
Java: Grand总时间(5次运行):12361毫秒,文件读取总时间:13304毫秒
c#:总时间(5次运行):17504毫秒,文件读取总时间:17956毫秒
Java: Grand总时间(5次运行):8947 ms,文件读取总时间:9186 ms
c#:总时间(5次运行):9884毫秒,文件读取总时间:10247毫秒
Java: Grand总时间(5次运行):9742毫秒,文件读取总时间:10111毫秒
c#:总时间(5次运行):10459毫秒,文件读取总时间:10696毫秒
Java:总时间(5次运行):2699毫秒,文件读取总时间:3127毫秒
c#:总时间(5次运行):2049毫秒,文件读取总时间:2182毫秒
Java: Grand总时间(5次运行):2992毫秒,文件读取总时间:3591毫秒
c#:总时间(5次运行):2049毫秒,文件读取总时间:2257毫秒
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上优化得更好?
我刚刚安装了Genymotion Android模拟器,它在Oracle VirtualBox中运行,同样,这个使用本机英特尔处理器,而不是模拟ARM处理器。与Intel HAX模拟器一样,c#在这里运行得更快。以下是我的结果:
< p > Java: 总时间(5次运行):2069 ms,文件读取总数:2248 ms < p > C #: 总时间(5次运行):1543 ms,文件读取总数:1642 ms
然后我注意到Xamarin有更新。Android beta版本4.7.11,发布说明中提到了Mono运行时的一些变化。决定快速测试一些ARM设备,有一个大惊喜——c#数字提高了:
Java: Grand总时间(5次运行):8103 ms,文件读取总时间:8569 ms
c#:总时间(5次运行):7951毫秒,文件读取总时间:8161毫秒
哇!c#现在比Java好?决定在我的Galaxy Note 2上重复测试:
Java:总时间(5次运行):9675毫秒,文件读取总时间:10028毫秒
c#:总时间(5次运行):9911毫秒,文件读取总时间:10104毫秒
这里的c#似乎只是稍微慢了一点,但这些数字让我犹豫了一下:为什么Note 2的处理器更快,但运行时间却比Nook HD+要长?答案是:节电模式。在Nook上,它是禁用的,在Note 2上是启用的。决定在禁用省电模式的情况下测试(与启用省电模式一样,它也会限制处理器的速度):
Java: Grand总时间(5次运行):7153毫秒,文件读取总时间:7459毫秒
c#:总时间(5次运行):6906毫秒,文件读取总时间:7070毫秒
现在,令人惊讶的是,c#在ARM处理器上也比Java略快。大的改进!
我们都知道,没有什么能比本机代码更快,我对我在Java或c#中的句子分配器的性能并不满意,特别是我需要改进它(从而使它更慢)。决定用c++重写。以下是我在Galaxy Note 2上禁用省电模式时本机和Java速度的一个小比较(由于其他原因,文件集比以前的测试要小):
< p > Java: 总时间(5次运行):3292 ms,文件读取总数:3454 ms < p >本地经验法则: 总时间(5次运行):537 ms,文件读取总:657 ms < p >本地的胳膊: 总时间(5次运行):458 ms,文件读取总:587 ms看起来对于我的特定测试,本机代码比Java快6到7倍。警告:不能在Android上使用std::regex类,所以必须自己编写专门的例程来搜索段落中断或html标签。我最初在PC上使用regex测试相同的代码,比Java快4到5倍。
唷!用char*或wchar*指针再次唤醒原始内存,我立刻感觉自己年轻了20岁!:)
(请参见下面,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 . regularexpresexpressions类没有我在Xamarin测试中使用的Split()函数,所以我使用了Java.Util.Regex类,而Java.Util.Regex. pattern .Split(),所以在代码中的这个特定位置,有这个小差异。不过应该不是什么大问题。Dot42编译为Dalvik (DEX)代码,因此它在Android上与Java原生合作,不需要像Xamarin那样从c#到Java的昂贵互操作。
为了比较,我也在ARM设备上运行测试——这里的Dot42代码“仅”比Xamarin c#慢2倍。以下是我的结果:
Java: Grand总时间(5次运行):12187毫秒,文件读取总时间:13200毫秒
Xamarin c#:总时间(5次运行):13935毫秒,文件读取总时间:14465毫秒
Dot42 c#:总时间(5次运行):26000 ms,文件读取总时间:27168 ms
Java: Grand总时间(5次运行):6895毫秒,文件读取总时间:7275毫秒
Xamarin c#:总时间(5次运行):6466毫秒,文件读取总时间:6720毫秒
Dot42 c#:总时间(5次运行):11185毫秒,文件读取总时间:11843毫秒
Java:总时间(5次运行):2389 ms,文件读取总时间:2770 ms
Xamarin c#:总时间(5次运行):1748毫秒,文件读取总时间:1933毫秒
Dot42 c#:总时间(5次运行):5150毫秒,文件读取总时间:5459毫秒
对我来说,同样有趣的是,Xamarin c#在新的ARM设备上比Java略快,而在旧的Nexus One上略慢。如果有人也想运行这些测试,请告诉我,我会在GitHub上更新源代码。如果能看到搭载英特尔处理器的真正Android设备的结果,那将是非常有趣的。
只是一个快速更新,用最新的Xamarin重新编译了基准应用程序。Android 4.8,以及今天发布的dot42 1.0.1.72更新-与之前报告的结果相比没有显著变化。
重新测试Dot42与罗伯特(从Dot42制造商)的端口我的Java代码到c#。在我最初为Xamarin所做的c#移植中,我用c#原生的List类替换了一些原生Java类,如lisstarray等。Robert没有我的Dot42源代码,所以他再次从Java移植,并在这些地方使用原始的Java类,这对Dot42有利,我猜是因为它运行在Dalvik VM中,像Java,而不是在Mono中,像Xamarin。现在Dot42的结果好多了。以下是我的测试日志:
2013年7月30日- Dot42在Dot42 c#中测试了更多Java类
英特尔模拟器,安卓4.2
Dot42, Greg's Code using StringBuilder.Replace() (as in Xamarin):
总时间(5次运行):3646 ms,文件读取总数:3830 msDot42,格雷格的代码使用String.Replace()(在Java和罗伯特的代码):
总时间(5次运行):3027 ms,文件读取总数:3206 msDot42,罗伯特的密码:
< p > Xamarin: < br > 总时间(5次运行):1373 ms,文件读取总数:1505 ms < p > Java: < br > 总时间(5次运行):1841 ms,文件读取总数:2044 ms
总时间(5次运行):1781 ms,文件读取总数:1999 msARM,三星Galaxy Note 2,省电关闭,安卓4.1.1
Dot42, Greg's Code using StringBuilder.Replace() (as in Xamarin):
总时间(5次运行):10875 ms,文件读取总数:11280 msDot42,格雷格的代码使用String.Replace()(在Java和罗伯特的代码):
总时间(5次运行):9710 ms,文件读取总:10097 msDot42,罗伯特的密码:
< p > Xamarin: < br > 总时间(5次运行):6201 ms,文件读取总:6476 ms < p > Java: < br > 总时间(5次运行):7141 ms,文件读取总数:7479 ms
总时间(5次运行):6279 ms,文件读取总:6622 ms
我仍然认为Dot42还有很长的路要走。拥有类似Java的类(例如ArrayList)和良好的性能将使代码从Java移植到c#稍微容易一些。然而,这是我不太可能经常做的事情。我宁愿使用现有的c#代码(库等),这将使用本机c#类(例如List),这将与当前的dot42代码执行缓慢,与Xamarin非常好。
格雷格