Я столкнулся с тем, что Xamarin утверждает, что их реализация Mono на Android и их скомпилированные приложения на С# быстрее, чем Java-код. Кто-нибудь выполнял фактические тесты на очень похожие Java и С# -код на разных платформах Android для проверки таких претензий, мог бы опубликовать код и результаты?
Добавлено 18 июня 2013 г.
Поскольку ответа не было и не удалось найти такие тесты, сделанные другими, решил сделать мои собственные тесты. К сожалению, мой вопрос остается "заблокирован", поэтому я не могу опубликовать это как ответ, только отредактируйте вопрос. Пожалуйста, проголосуйте, чтобы повторно открыть этот вопрос. Для С# я использовал Xamarin.Android ver. 4.7.09001 (бета). Исходный код, все данные, которые я использовал для тестирования, и скомпилированные пакеты APK находятся в GitHub:
Java: https://github.com/gregko/TtsSetup_Java
С#: https://github.com/gregko/TtsSetup_C_sharp
Если кто-то захочет повторить мои тесты на других устройствах или эмуляторах, мне было бы интересно также изучить результаты.
Результаты моего тестирования
Я портировал класс экстрактора предложения на С# (из моего приложения @Voice Aloud Reader) и запускал некоторые тесты на 10 html файлах на английском, русском, французском, польском и чешском языках. Каждый прогон выполнялся 5 раз на всех 10 файлах, а общее время для трех разных устройств и одного эмулятора размещено ниже. Я тестировал только "Release", но без отладки.
HTC Nexus One Android 2.3.7 (API 10) - CyanogenMod ROM
Java: общее время (5 прогонов): 12361 мс, при чтении файла: 13304 мс
С#: общее время (5 прогонов): 17504 мс, при чтении файла: 17956 мс
Samsung Galaxy S2 SGH-I777 (Android 4.0.4, API 15) - CyanogenMod ROM
Java: общее время (5 прогонов): 8947 мс, с общим количеством файлов: 9186 мс
С#: общее время (5 прогонов): 9884 мс, с общим объемом файла: 10247 мс
Samsung GT-N7100 (Android 4.1.1 JellyBean, API 16) - Samsung ROM
Java: общее время (5 прогонов): 9742 мс, при чтении файла: 10111 мс
С#: общее время (5 пробегов): 10459 мс, с общим количеством файлов: 10696 мс
Эмулятор - Intel (Android 4.2, API 17)
Java: общее время (5 прогонов): 2699 мс, при чтении файла: 3127 мс
С#: общее общее время (5 прогонов): 2049 мс, при чтении файла: 2182 мс
Эмулятор - Intel (Android 2.3.7, API 10)
Java: общее время (5 прогонов): 2992 мс, при чтении файла: 3591 мс
С#: общее время (5 прогонов): 2049 мс, с общим объемом файла: 2257 мс
Emulator - Arm (Android 4.0.4, API 15)
Java: общее время (5 прогонов): 41751 мс, при чтении файла: 43866 мс
С#: общее время (5 прогонов): 44136 мс, при чтении файла: 45109 мс
Краткое обсуждение
Мой тестовый код содержит в основном текстовое разбор, замену и поиск в регулярном выражении, возможно, для другого кода (например, более числовые операции) результаты будут разными. На всех устройствах с ARM-процессорами Java работает лучше, чем Xamarin С#. Самая большая разница была в Android 2.3, где код С# запускался прибл. 70% скорости Java.
В эмуляторе Intel (с технологией Intel HAX, эмулятор работает в режиме быстрого virt), код Xamarin С# работает с моим примером кода намного быстрее, чем Java - примерно в 1,35 раза быстрее. Может ли Mono виртуальный машинный код и библиотеки гораздо лучше оптимизированы для Intel, чем на ARM?
Изменить 8 июля 2013 г.
Я только что установил эмулятор Genymotion Android, который работает в Oracle VirtualBox, и снова этот использует собственный процессор Intel, а не эмулятор ARM-процессора. Как и в случае с эмулятором Intel HAX, снова С# работает здесь намного быстрее. Вот мои результаты:
Эмулятор Genymotion - Intel (Android 4.1.1, API 16)
Java: Общее общее время (5 пробегов): 2069 мс, при чтении файла: 2248 мс
С#: Общее общее время (5 пробегов): 1543 мс, при чтении файла: 1642 мс
Затем я заметил, что было обновлено бета-версия Xamarin.Android, версия 4.7.11, с примечаниями к выпуску, в которых упоминаются некоторые изменения в среде исполнения Mono. Решили быстро протестировать некоторые устройства ARM и большой сюрприз - улучшены номера С#:
BN Nook XD +, ARM (Android 4.0)
Java: общее время (5 прогонов): 8103 мс, с общим объемом файла: 8569 мс
С#: общее время (5 прогонов): 7951 мс, с общим количеством файлов: 8161 мс
Ничего себе! С# теперь лучше, чем Java? Решил повторить тест на моей Галактике Примечание 2:
Samsung Galaxy Note 2 - ARM (Android 4.1.1)
Java: общее время (5 прогонов): 9675 мс, общее число файлов: 10028 мс
С#: общее время (5 прогонов): 9911 мс, при чтении файла: 10104 мс
Здесь С# выглядит немного медленнее, но эти цифры дали мне паузу: почему время больше, чем на Nook HD +, хотя Note 2 имеет более быстрый процессор? Ответ: режим энергосбережения. На Nook он отключен, включен Примечание 2. Решено протестировать с отключенным режимом энергосбережения (как при включенном, оно также ограничивает скорость процессора):
Samsung Galaxy Note 2 - ARM (Android 4.1.1), энергосбережение отключено
Java: общее время (5 прогонов): 7153 мс, при чтении файла: 7459 мс
С#: общее время (5 прогонов): 6906 мс, с общим количеством файлов: 7070 мс
Теперь, что удивительно, С# немного быстрее, чем Java на процессоре ARM. Большое улучшение!
Редактировать 12 июля 2013 г.
Мы все знаем, что ничто не сравнится с собственным кодом для скорости, и меня не устраивало производительность моего разделителя предложений в Java или С#, особенно, что мне нужно его улучшить (и тем самым сделать его еще медленнее). Решил переписать его на С++. Вот небольшой (т.е. Меньший набор файлов, чем предыдущие тесты, по другим причинам) сравнение скорости родной и Java на моей Galaxy Note 2 с отключенным режимом энергосбережения:
Java: Общее общее время (5 пробегов): 3292 мс, при чтении файла: 3454 мс
Нативный палец: Общее общее время (5 пробегов): 537 мс, при чтении файла: 657 мс
Родная рука: Общее общее время (5 пробегов): 458 мс, при чтении файла: 587 мс
Похоже, что для моего конкретного теста собственный код в 6-7 раз быстрее, чем Java. Caveat: не мог использовать класс std:: regex на Android, поэтому мне пришлось писать собственные специализированные процедуры поиска абзацев breaks или html-тегов. Мои начальные тесты одного и того же кода на ПК с использованием regex были примерно в 4-5 раз быстрее, чем Java.
Уф! Пробуждая необработанную память с помощью указателей char * или wchar *, я мгновенно почувствовал себя на 20 лет моложе!:)
Редактировать 15 июля 2013 г.
(см. ниже, с изменениями от 7/30/2013, для получения гораздо лучших результатов с Dot42)
С некоторым трудом мне удалось перенести мои тесты С# на Dot42 (версия 1.0.1.71 beta), еще одна платформа С# для Android. Предварительные результаты показывают, что код Dot42 примерно в 3 раза (3 раза) медленнее, чем Xamarin С# (версия 4.7.11), на эмуляторе Intel Android. Одна из проблем заключается в том, что класс System.Text.RegularExpressions в Dot42 не имеет функции Split(), которую я использовал в тестах Xamarin, поэтому вместо этого я использовал класс Java.Util.Regex и Java.Util.Regex.Pattern.Split(), поэтому в этом конкретном месте в коде есть эта небольшая разница. Однако не должно быть большой проблемой. Dot42 компилируется в код Dalvik (DEX), поэтому он взаимодействует с Java на Android изначально, не требует дорогостоящего взаимодействия с С# на Java, например Xamarin.
Просто для сравнения, я также запускаю тест на устройствах ARM - здесь код Dot42 "только" 2x медленнее, чем Xamarin С#. Вот мои результаты:
HTC Nexus One Android 2.3.7 (ARM)
Java: общее время (5 прогонов): 12187 мс, при чтении файла: 13200 мс
Xamarin С#: общее время (5 пробегов): 13935 мс, при чтении файла: 14465 мс
Dot42 С#: общее время (5 прогонов): 26000 мс, с общим объемом файла: 27168 мс
Samsung Galaxy Note 2, Android 4.1.1 (ARM)
Java: общее время (5 прогонов): 6895 мс, при чтении файла: 7275 мс
Xamarin С#: общее время (5 пробегов): 6466 мс, с общим количеством файлов: 6720 мс
Dot42 С#: общее время (5 прогонов): 11185 мс, с общим объемом файла: 11843 мс
эмулятор Intel, Android 4.2 (x86)
Java: общее время (5 прогонов): 2389 мс, с общим объемом файла: 2770 мс
Xamarin С#: общее время (5 пробегов): 1748 мс, с общим количеством файлов: 1933 мс
Dot42 С#: общее время (5 прогонов): 5150 мс, с общим объемом файла: 5459 мс
Мне также было интересно отметить, что Xamarin С# немного быстрее, чем Java на более новом устройстве ARM, и немного медленнее на старом Nexus One. Если кто-то захочет также запустить эти тесты, сообщите мне, и я обновлю источники на GitHub. Было бы особенно интересно увидеть результаты с реального Android-устройства с процессором Intel.
Обновление 7/26/2013
Просто быстрое обновление, скомпилированное с помощью тестов с последними версиями Xamarin.Android 4.8, а также с выпуском dot42 1.0.1.72, выпущенным сегодня - никаких существенных изменений в результатах, о которых сообщалось ранее.
Обновление 7/30/2013 - лучшие результаты для dot42
Повторно протестировано Dot42 с Робертом (от производителей dot42) порт моего Java-кода до С#. В моем порт С#, первоначально сделанный для Xamarin, я заменил некоторые родные классы Java, такие как ListArray, с классом List, родным С# и т.д. У Robert не было моего исходного кода Dot42, поэтому он портировал его снова с Java и использовал оригинальные классы Java в такие места, которые приносят пользу Dot42, я думаю, потому что он работает в Dalvik VM, как Java, а не в Mono, как Xamarin. Теперь результаты Dot42 намного лучше. Вот журнал из моего тестирования:
7/30/2013 - тесты Dot42 с большим количеством классов Java в Dot42 С#
эмулятор Intel, Android 4.2
Dot42, Greg Code с помощью StringBuilder.Replace() (как в Xamarin):
Общее общее время (5 пробегов): 3646 мс, при чтении файла: 3830 мсDot42, Greg Code с использованием String.Replace() (как в коде Java и Robert):
Общее общее время (5 прогонов): 3027 мс, при чтении файла: 3206 мсDot42, Robert Код:
Общее общее время (5 пробегов): 1781 мс, при чтении файла: 1999 мсXamarin:
Общее общее время (5 пробегов): 1373 мс, при чтении файла: 1505 мсJava:
Общее общее время (5 пробегов): 1841 мс, при чтении файла: 2044 мсARM, Samsung Galaxy Note 2, энергосбережение, Android 4.1.1
Dot42, Greg Code с помощью StringBuilder.Replace() (как в Xamarin):
Общее общее время (5 пробегов): 10875 мс, при чтении файла: 11280 мсDot42, Greg Code с использованием String.Replace() (как в коде Java и Robert):
Общее общее время (5 пробегов): 9710 мс, при чтении файла: 10097 мсDot42, Robert Код:
Общее общее время (5 пробегов): 6279 мс, при чтении файла: 6622 мсXamarin:
Общее общее время (5 пробегов): 6201 мс, при чтении файла: 6476 мсJava:
Общее общее время (5 пробегов): 7141 мс, при чтении файла: 7479 мс
Я все еще думаю, что Dot42 имеет долгий путь. Наличие Java-подобных классов (например, ArrayList) и хорошая производительность с ними сделают код переноса с Java на С# немного легче. Тем не менее, это то, что я вряд ли буду делать много. Я бы предпочел использовать существующий код С# (библиотеки и т.д.), Который будет использовать собственные классы С# (например, List), и это будет медленно работать с текущим кодом dot42 и очень хорошо с Xamarin.
Грег