有没有人有基准(代码和结果)比较用Xamarin C#和Java编写的Android应用程序的性能?

我遇到了Xamarin声称他们在Android和他们的C#编译的应用程序上的Mono实现比Java代码更快。 有没有人在不同的Android平台上对非常相似的Java和C#代码进行实际的基准testing来validation这些声明,可以发布代码和结果?

2013年6月18日新增

既然没有答案,也找不到别人所做的基准,就决定做我自己的testing。 不幸的是,我的问题仍然是“locking”,所以我不能发表这个答案,只能编辑问题。 请投票重新提出这个问题。 对于C#,我使用Xamarin.Android版本。 4.7.09001(testing版) 源代码,用于testing的所有数据以及已编译的APK软件包位于GitHub上:

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

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

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

从我的testing结果

我将我的句子提取器类移植到C#(从我的@语音朗读器应用程序),并对英语,俄语,法语,波兰语和捷克语10个html文件运行一些testing。 每个运行在所有10个文件上执行5次,下面列出3个不同设备和一个模拟器的总时间。 我只testing了“Release”版本,没有启用debugging。

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果冻豆,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次):2992ms,文件读取总数:3591ms

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

模拟器 – arm(Android 4.0.4,API 15)

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

C#:累计总时间(5次):44136毫秒,文件读数总计:45109毫秒

简要讨论

我的testing代码主要包含文本parsing,replace和正则expression式search,也许对于其他代码(例如更多数字操作),结果将会不同。 在所有使用ARM处理器的设备上,Java比Xamarin C#代码performance得更好。 最大的区别是在Android 2.3下,C#代码运行在约。 Java速度的70%。

在英特尔仿真器上(使用英特尔HAX技术,仿真器以快速虚拟模式运行),Xamarin C#代码运行我的示例代码比Java快得多 – 大约快1.35倍。 也许单声道虚拟机代码和库在英特尔上比在ARM上更好地优化?

编辑2013年7月8日

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

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

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

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

然后我注意到有一个更新Xamarin.Androidtesting版,版本4.7.11,发行说明提及Mono运行时的一些变化。 决定快速testing一些ARM设备,并大吃一惊 – C#号码改进了:

BN Nook XD +,ARM(Android 4.0)

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

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

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

三星Galaxy Note 2 – ARM(Android 4.1.1)

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

C#:累计总时间(5次):9911ms,文件读数总计:10104ms

这里C#似乎只是稍微慢一些,但这些数字给了我一个暂停:为什么时间比Nook HD +更长,尽pipeNote 2有一个更快的处理器? 答案是:省电模式。 在angular落,它被禁用,在注2 – 启用。 决定在禁用省电模式的情况下进行testing(启用时也会限制处理器速度):

三星Galaxy Note 2 – ARM(Android 4.1.1),禁用了省电function

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

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

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

编辑2013年7月12日

我们都知道,没有什么比原生代码更快的速度,而且我对Java或C#中的语句分割器的性能还不满意,特别是我需要改进它(并且因此使其更慢)。 决定用C ++重新编写它。 这里是一个小的(比以前的testing,由于其他原因,文件的一个较小的一组)文件比较我的Galaxy Note 2本机与Java的速度与省电模式禁用:

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

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

原生arm:总计总时间(5次):458毫秒,文件读数总计:587毫秒

看起来像我的特定testing,本机代码比Java快6到7倍。 警告:不能在Android上使用std :: regex类,所以不得不编写我自己的search段落分隔符或html标签的特殊例程。 我使用正则expression式在PC上对同一代码进行的初始testing比Java快4到5倍。

唷! 用char *或wchar *指针再次唤醒原始内存,我立刻感觉到了20岁! 🙂

编辑2013年7月15日

(请参阅下文,编辑2013年7月30日,Dot42更好的结果)

有一些困难,我试图把我的C#testing移植到Dot42(版本1.0.1.71testing版),Android的另一个C#平台。 初步结果显示,在英特尔Android仿真器上,Dot42代码比Xamarin C#(v.4.7.11)慢3倍(3倍)。 一个问题是,Dot42中的System.Text.RegularExpressions类没有我在Xamarintesting中使用的Split()函数,所以我使用了Java.Util.Regex类,而Java.Util.Regex.Pattern.Split ),所以在代码中的这个特定的地方有这个小的差异。 应该不是一个大问题。 Dot42编译为Dalvik(DEX)代码,所以它本身就和Android上的Java配合,不需要像Xamarin那样从C#到Java的昂贵的interop。

仅仅为了比较,我也在ARM设备上运行testing – 这里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毫秒

对我来说,有趣的是在新的ARM设备上Xamarin C#比Java稍微快一点,而旧版的Nexus One稍慢。 如果有人想要运行这些testing,请让我知道,我会更新GitHub上的来源。 使用英特尔处理器的真实Android设备的结果将是特别有趣的。

更新7/26/2013

只是一个快速更新,由基准应用程序与最新的Xamarin.Android 4.8,以及今天发布的dot42 1.0.1.72更新重新编译 – 没有从以前的报告结果的重大变化。

更新7/30/2013 – dot42更好的结果

用我的Java代码的Robert(从dot42制造商)端口重新testingDot42到C#。 在我最初为Xamarin完成的C#端口中,我用一些本地Java类(如ListArray)和C#原生的List类replace了它们。Robert没有我的Dot42源代码,所以他再次从Java移植它,并使用原始Java类这些地方,有利于Dot42,我猜是因为它运行在Dalvik虚拟机,像Java,而不是单声道,如Xamarin。 现在Dot42的结果好多了。 以下是我testing的日志:

2013年7月30日 – Dot42在Dot42中testing更多的Java类C#

英特尔仿真器,Android 4.2

Dot42,格雷格的代码使用StringBuilder.Replace()(如Xamarin):
总时间(5次):3646毫秒,文件读数总计:3830毫秒

Dot42,格雷格的代码使用String.Replace()(如在Java和罗伯特的代码):
总时间(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()(如Xamarin):
总时间(5次):10875毫秒,文件读数总计:11280毫秒

Dot42,格雷格的代码使用String.Replace()(如在Java和罗伯特的代码):
总时间(5次):9710毫秒,文件读数总计:10097毫秒

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

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

Java的:
总时间(5次):7141毫秒,文件读数总计:7479毫秒

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

格雷格

是的,Xamarin的Mono虚拟机比谷歌在Android上使用的Dalvik更令人印象深刻。 我已经testing了HTC Flyer和Acer Iconia Tab平板电脑,通过Mono针对Java Dalvik对Android的C#端口进行基准testing,并通过C#实现了Android,真正打破了基于Java的Dalvik。

I came across this interesting post 

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

Android应用性能

iOS应用程序性能

希望这个信息有帮助。

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

简而言之,Xamarin有时比本地代码更好。 他testing了应用程序大小,加载时间,从Azure服务和素数计算加载列表。

请享用!

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

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

我们发现,Xamarin C#中的I / O大约比Java慢2倍。 我们的应用程序严重I / O限制。 我们还没有find原因,但目前我们认为这是由于编组。 虽然大部分时间我们都试图呆在Mono虚拟机中,但我们不知道Mono实际上是如何访问磁盘的。

它也告诉我们我们的C#代码使用SQLite.NET( https://github.com/praeclarum/sqlite-net )。 使用SQLite.NET代码的相同的提取速度也比使用Android的Java SQLite包装器慢两倍。 查看源代码后,它似乎直接绑定到C .dll,所以我不知道为什么它太慢了。 一种可能性是从本地到Java的编组string可能比在Xamarin上的本地C#更快。

这是相当旧的testing,但可以是相关的: https : //github.com/EgorBo/Xamarin.Android-vs-Java

算术testing

在这里输入图像说明

集合,generics,自定义值types

在这里输入图像说明

使用string

在这里输入图像说明

性能

性能是一个模糊的词,如果你没有定义你的性能是什么意思,如果它是简单的计算性能Xamarin可以比Java更快取决于计算的性质。

Android本身带有multipeforms来执行代码:

  • RenderScript(CPU和GPU)
  • Java(SDK)
  • C ++(NDK)
  • OpenGL(GPU)

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

但另一方面,如果你想衡量真实的使用性能Java是propbaby会更快,然后Xamarin。

Xamarin以及为什么它会变慢

在比较Xamarin和普通的Java应用程序时,Xamarin的性能可能会更快,因为它可能会变慢。

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

有几个不同types的绑定是重要的知道:

  • JNI(Java本地接口):在许多android应用程序中用于在Java代码(SDK)和本机C ++代码(NDK)之间进行交互的绑定。
  • MCW(托pipe可调用包装器): Xamarin提供的用于从托pipeC#代码到Java代码(Android运行时)的接口的绑定。
  • ACW(Android Callable Wrappers): Xamarin提供的一个绑定,用于从Java代码(Android运行时)接口到托pipeC#代码。

有关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 ++方法要快很多倍。

有人做了一个性能testing来计算平均一个JNI调用需要多less个Java操作: 做一个JNI调用的数量开销是多less?

但是,不仅JNI呼叫成本高,MCW和ACW的呼叫也是如此。 真实世界的Xamarin应用程序使用绑定进行多次调用,因为这个真实世界中的Xamarin应用程序的使用可能(并且一般而言)比普通的旧式Java应用程序慢。 然而,取决于Xamarin应用程序的devise,用户很可能不会注意到这种差异。

TLDR /结论: Xamarin需要使用alsorting绑定,这是时间成本高昂的。

除了绑定之外,在讨论真实世界的性能时,还有许多其他因素,例如:二进制大小,在应用程序中加载内存,I / O操作等等。 调查这些事情的博客文章可以在这里find: https : //magenic.com/thinking/mobile-development-platform-performance-part-2-native-cordova-classic-xamarin-xamarin-forms