Я сталкивался с утверждениями Xamarin о том, что их реализация Mono на Android и их приложения, скомпилированные на C #, работают быстрее, чем код Java. Кто-нибудь выполнил реальные тесты на очень похожих кодах Java и C # на разных платформах Android, чтобы проверить такие утверждения, мог опубликовать код и результаты?
Добавлено 18 июня 2013 г.
Так как ответа не было и не удалось найти такие тесты, сделанные другими, я решил провести свои собственные тесты. К сожалению, мой вопрос остается «заблокированным», поэтому я не могу опубликовать его в качестве ответа, а только отредактировать вопрос. Пожалуйста, проголосуйте, чтобы снова открыть этот вопрос. Для 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 на английском, русском, французском, польском и чешском языках. Каждый запуск был выполнен 5 раз для всех 10 файлов, и общее время для 3 различных устройств и одного эмулятора опубликовано ниже. Я тестировал только сборки "Release", без включенной отладки.
HTC Nexus One Android 2.3.7 (API 10) - CyanogenMod ROM
Java: общее общее время (5 запусков): 12361 мс, общее время чтения файла: 13304 мс
C #: общее общее время (5 запусков): 17504 мс, общее чтение файла: 17956 мс
Samsung Galaxy S2 SGH-I777 (Android 4.0.4, API 15) - ПЗУ CyanogenMod
Java: общее общее время (5 запусков): 8947 мс, общее время чтения файла: 9186 мс
C #: общее общее время (5 запусков): 9884 мс, общее время чтения файла: 10247 мс
Samsung GT-N7100 (Android 4.1.1 JellyBean, API 16) - Samsung ROM
Java: общее общее время (5 запусков): 9742 мс, общее время чтения файла: 10111 мс
C #: общее общее время (5 запусков): 10459 мс, общее чтение файла: 10696 мс
Эмулятор - Intel (Android 4.2, API 17)
Java: общее общее время (5 запусков): 2699 мс, общее время чтения файла: 3127 мс
C #: общее общее время (5 запусков): 2049 мс, общее чтение файла: 2182 мс
Эмулятор - Intel (Android 2.3.7, API 10)
Java: общее общее время (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 # работал на ок. 70% скорости Java.
В эмуляторе Intel (с технологией Intel HAX эмулятор работает в режиме быстрого виртуального выхода) код Xamarin C # выполняет мой пример кода намного быстрее, чем Java - примерно в 1,35 раза быстрее. Может быть, код и библиотеки виртуальной машины Mono намного лучше оптимизированы для Intel, чем для ARM?
Редактировать 8 июля 2013 г.
Я только что установил эмулятор Android Genymotion, который работает в Oracle VirtualBox, и снова этот использует собственный процессор Intel, а не процессор ARM. Как и в случае с эмулятором Intel HAX, снова C # работает здесь намного быстрее. Вот мои результаты:
Эмулятор Genymotion - Intel (Android 4.1.1, API 16)
Java: общее общее время (5 запусков): 2069 мс, общее время чтения файла: 2248 мс
C #: общее общее время (5 запусков): 1543 мс, общее чтение файла: 1642 мс
Затем я заметил, что появилось обновление для бета-версии Xamarin.Android, версия 4.7.11, с примечаниями к выпуску, в которых упоминались также некоторые изменения во время выполнения Mono. Решил быстро протестировать некоторые устройства ARM, и большой сюрприз - улучшилось число C #:
BN Nook XD +, ARM (Android 4.0)
Java: общее общее время (5 запусков): 8103 мс, общее время чтения файла: 8569 мс
C #: общее общее время (5 запусков): 7951 мс, общее чтение файла: 8161 мс
Вот Это Да! C # теперь лучше, чем Java? Решил повторить тест на моем Galaxy Note 2:
Samsung Galaxy Note 2 - ARM (Android 4.1.1)
Java: общее общее время (5 запусков): 9675 мс, общее чтение файла: 10028 мс
C #: общее общее время (5 запусков): 9911 мс, с общим чтением файла: 10104 мс
Здесь C # кажется немного медленнее, но эти цифры дали мне паузу: почему время длиннее, чем на Nook HD +, хотя Note 2 имеет более быстрый процессор? Ответ: режим энергосбережения. На Nook он был отключен, на Note 2 - включен. Решили протестировать с отключенным режимом энергосбережения (как и при включенном, он также ограничивает скорость процессора):
Samsung Galaxy Note 2 - ARM (Android 4.1.1), энергосбережение отключено
Java: общее общее время (5 запусков): 7153 мс, общее время чтения файла: 7459 мс
C #: общее общее время (5 запусков): 6906 мс, общее чтение файла: 7070 мс
Теперь, что удивительно, C # немного быстрее, чем Java на процессоре ARM. Большое улучшение!
Изменить 12 июля 2013 г.
Все мы знаем, что ничто не сравнится с быстродействием нативного кода, и я не был удовлетворен производительностью моего сплиттера предложений в Java или C #, особенно в том, что мне нужно его улучшить (и, следовательно, сделать его еще медленнее). Решил переписать это на C ++. Вот небольшое (т. Е. Меньший набор файлов, чем предыдущие тесты, по другим причинам) сравнение скорости нативной и Java на моей Galaxy Note 2 с отключенным режимом энергосбережения:
Java: общее общее время (5 запусков): 3292 мс, общее чтение файла: 3454 мс
Собственный большой палец: общее общее время (5 запусков): 537 мс, общее время чтения файла: 657 мс
Родная рука: Общее общее время (5 запусков): 458 мс, с общим чтением файла: 587 мс
Похоже, для моего конкретного теста нативный код работает в 6-7 раз быстрее, чем Java. Предостережение: не могу использовать класс std :: regex на Android, поэтому пришлось написать свои собственные специализированные процедуры для поиска разрывов абзацев или HTML-тегов. Мои начальные тесты того же кода на ПК с использованием регулярных выражений, были примерно в 4-5 раз быстрее, чем Java.
Уф! Пробуждая сырую память с помощью указателей char * или wchar *, я сразу почувствовал себя на 20 лет моложе! :)
Редактировать 15 июля 2013 г.
(Пожалуйста, смотрите ниже, с изменениями от 30.07.2013, для гораздо лучших результатов с Dot42)
С некоторым трудом мне удалось перенести свои тесты C # на Dot42 (версия 1.0.1.71 бета), еще одну платформу C # для Android. Предварительные результаты показывают, что код Dot42 примерно в 3 раза (в 3 раза) медленнее, чем Xamarin C # (v. 4.7.11), на эмуляторе Intel Android. Одна из проблем заключается в том, что класс System.Text.RegularExpressions в Dot42 не имеет функции Split (), которую я использовал в тестах Xamarin, поэтому вместо этого я использовал класс Java.Util.Regex и Java.Util.Regex.Pattern.Split (). Таким образом, в этом конкретном месте кода есть небольшая разница. Не должно быть большой проблемой, хотя. Dot42 компилируется в код Dalvik (DEX), поэтому он изначально взаимодействует с Java на Android, не требует дорогостоящего взаимодействия с C # до Java, такого как Xamarin.
Для сравнения, я также запускаю тест на устройствах ARM - здесь код Dot42 "всего лишь" в 2 раза медленнее, чем Xamarin C #. Вот мои результаты:
HTC Nexus One Android 2.3.7 (ARM)
Java: общее общее время (5 запусков): 12187 мс, общее время чтения файла: 13200 мс
Xamarin C #: общее общее время (5 прогонов): 13935 мс, с общим чтением файла: 14465 мс
Dot42 C #: общее общее время (5 запусков): 26000 мс, общее чтение файла: 27168 мс
Samsung Galaxy Note 2, Android 4.1.1 (ARM)
Java: общее время (5 запусков): 6895 мс, общее время чтения файла: 7275 мс
Xamarin C #: общее общее время (5 запусков): 6466 мс, общее время чтения файла: 6720 мс
Dot42 C #: общее общее время (5 запусков): 11185 мс, общее чтение файла: 11843 мс
Эмулятор Intel, Android 4.2 (x86)
Java: общее общее время (5 запусков): 2389 мс, общее время чтения файла: 2770 мс
Xamarin C #: общее общее время (5 запусков): 1748 мс, общее чтение файла: 1933 мс
Dot42 C #: общее общее время (5 запусков): 5150 мс, общее чтение файла: 5459 мс
Мне было также интересно отметить, что Xamarin C # немного быстрее Java на более новом устройстве ARM и немного медленнее на старом Nexus One. Если кто-то также хотел бы запустить эти тесты, пожалуйста, дайте мне знать, и я обновлю исходники на GitHub. Было бы особенно интересно увидеть результаты реального устройства Android с процессором Intel.
Обновление 26.07.2013
Просто быстрое обновление, перекомпилированное эталонными приложениями с последним Xamarin.Android 4.8, а также с вышедшим сегодня обновлением dot42 1.0.1.72 - никаких существенных изменений по сравнению с результатами, о которых сообщалось ранее.
Обновление 30.07.2013 - лучшие результаты для dot42
Перепроверено Dot42 с портом Роберта (от создателей dot42) моего Java-кода на C #. В моем C # -порте, изначально созданном для Xamarin, я заменил некоторые собственные классы Java, такие как ListArray, на класс List, родной для C # и т. Д. У Роберта не было моего исходного кода Dot42, поэтому он снова перенес его из Java и использовал оригинальные классы Java в такие места, которые приносят пользу Dot42, я думаю, потому что он работает в Dalvik VM, как Java, а не в Mono, как Xamarin. Теперь результаты Dot42 намного лучше. Вот журнал из моего тестирования:
30.07.2013 - Тесты Dot42 с большим количеством классов Java в Dot42 C #
Эмулятор Intel, 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, Samsung 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 # (например, List), и который будет работать медленно с текущим кодом dot42 и очень хорошо с Xamarin.
Greg