Я столкнулся с тем, что Xamarin утверждает, что их реализация Mono на Android и их скомпилированные приложения на С# быстрее, чем Java-код. Кто-нибудь выполнял фактические тесты на очень похожие Java и С# -код на разных платформах Android для проверки таких претензий, мог бы опубликовать код и результаты?
Поскольку ответа не было и не удалось найти такие тесты, сделанные другими, решил сделать мои собственные тесты. К сожалению, мой вопрос остается "заблокирован", поэтому я не могу опубликовать это как ответ, только отредактируйте вопрос. Пожалуйста, проголосуйте, чтобы повторно открыть этот вопрос. Для С# я использовал 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", но без отладки.
Java: общее время (5 прогонов): 12361 мс, при чтении файла: 13304 мс
С#: общее время (5 прогонов): 17504 мс, при чтении файла: 17956 мс
Java: общее время (5 прогонов): 8947 мс, с общим количеством файлов: 9186 мс
С#: общее время (5 прогонов): 9884 мс, с общим объемом файла: 10247 мс
Java: общее время (5 прогонов): 9742 мс, при чтении файла: 10111 мс
С#: общее время (5 пробегов): 10459 мс, с общим количеством файлов: 10696 мс
Java: общее время (5 прогонов): 2699 мс, при чтении файла: 3127 мс
С#: общее общее время (5 прогонов): 2049 мс, при чтении файла: 2182 мс
Java: общее время (5 прогонов): 2992 мс, при чтении файла: 3591 мс
С#: общее время (5 прогонов): 2049 мс, с общим объемом файла: 2257 мс
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?
Я только что установил эмулятор Genymotion Android, который работает в Oracle VirtualBox, и снова этот использует собственный процессор Intel, а не эмулятор ARM-процессора. Как и в случае с эмулятором Intel HAX, снова С# работает здесь намного быстрее. Вот мои результаты:
Java: Общее общее время (5 пробегов): 2069 мс, при чтении файла: 2248 мс
С#: Общее общее время (5 пробегов): 1543 мс, при чтении файла: 1642 мс
Затем я заметил, что было обновлено бета-версия Xamarin.Android, версия 4.7.11, с примечаниями к выпуску, в которых упоминаются некоторые изменения в среде исполнения Mono. Решили быстро протестировать некоторые устройства ARM и большой сюрприз - улучшены номера С#:
Java: общее время (5 прогонов): 8103 мс, с общим объемом файла: 8569 мс
С#: общее время (5 прогонов): 7951 мс, с общим количеством файлов: 8161 мс
Ничего себе! С# теперь лучше, чем Java? Решил повторить тест на моей Галактике Примечание 2:
Java: общее время (5 прогонов): 9675 мс, общее число файлов: 10028 мс
С#: общее время (5 прогонов): 9911 мс, при чтении файла: 10104 мс
Здесь С# выглядит немного медленнее, но эти цифры дали мне паузу: почему время больше, чем на Nook HD +, хотя Note 2 имеет более быстрый процессор? Ответ: режим энергосбережения. На Nook он отключен, включен Примечание 2. Решено протестировать с отключенным режимом энергосбережения (как при включенном, оно также ограничивает скорость процессора):
Java: общее время (5 прогонов): 7153 мс, при чтении файла: 7459 мс
С#: общее время (5 прогонов): 6906 мс, с общим количеством файлов: 7070 мс
Теперь, что удивительно, С# немного быстрее, чем Java на процессоре ARM. Большое улучшение!
Мы все знаем, что ничто не сравнится с собственным кодом для скорости, и меня не устраивало производительность моего разделителя предложений в 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 лет моложе!:)
(см. ниже, с изменениями от 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 С#. Вот мои результаты:
Java: общее время (5 прогонов): 12187 мс, при чтении файла: 13200 мс
Xamarin С#: общее время (5 пробегов): 13935 мс, при чтении файла: 14465 мс
Dot42 С#: общее время (5 прогонов): 26000 мс, с общим объемом файла: 27168 мс
Java: общее время (5 прогонов): 6895 мс, при чтении файла: 7275 мс
Xamarin С#: общее время (5 пробегов): 6466 мс, с общим количеством файлов: 6720 мс
Dot42 С#: общее время (5 прогонов): 11185 мс, с общим объемом файла: 11843 мс
Java: общее время (5 прогонов): 2389 мс, с общим объемом файла: 2770 мс
Xamarin С#: общее время (5 пробегов): 1748 мс, с общим количеством файлов: 1933 мс
Dot42 С#: общее время (5 прогонов): 5150 мс, с общим объемом файла: 5459 мс
Мне также было интересно отметить, что Xamarin С# немного быстрее, чем Java на более новом устройстве ARM, и немного медленнее на старом Nexus One. Если кто-то захочет также запустить эти тесты, сообщите мне, и я обновлю источники на GitHub. Было бы особенно интересно увидеть результаты с реального Android-устройства с процессором Intel.
Просто быстрое обновление, скомпилированное с помощью тестов с последними версиями Xamarin.Android 4.8, а также с выпуском dot42 1.0.1.72, выпущенным сегодня - никаких существенных изменений в результатах, о которых сообщалось ранее.
Повторно протестировано 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.
Грег
Да, виртуальная машина Xamarin Mono более впечатляющая, чем Google Dalvik, используемая в Android. Я протестировал его с помощью HTC Flyer и планшетов Acer Iconia Tab, чтобы сравнить С# порт Android с помощью Mono против Java Dalvik, с реализацией С# для Android и, действительно, запуская Java-платформу Dalvik.
I came across this interesting post
https://medium.com/@harrycheung/mobile-app-performance-redux-e512be94f976#.kfbauchtz
Надеемся, что эта информация поможет.
Это еще один обновленный пост в блоге, который я хотел бы поделиться с вами. Он сравнивает Xamarin с родным кодом и Cordova как с IO, так и с Android.
В двух словах, Xamarin выполняет иногда лучше, чем собственный код. Он тестировал размер приложения, время загрузки, загрузку списка из службы Azure и вычисления простых чисел.
Наслаждайтесь!
Изменить: я обновил мертвую ссылку, и я заметил, что есть часть 2
Недавно мы исследовали использование Xamarin для приложения. Мы использовали код С#, который мы уже писали для версии нашего приложения Windows RT. Некоторые детали были переписаны для версии Android.
Мы обнаружили, что I/O в Xamarin С# примерно в 2 раза медленнее, чем Java. Наше приложение сильно связано с I/O. Мы еще не обнаружили причину этого, но на данный момент мы предполагаем, что это связано с маршалингом. Хотя мы стараемся оставаться внутри Mono VM большую часть времени, мы не знаем, как Mono фактически обращается к диску.
Также говорится, что наш С# -код использует SQLite.NET(https://github.com/praeclarum/sqlite-net). Идентичные выборки с использованием кода SQLite.NET также в 2 раза медленнее, чем использование оболочки Javaite SQLite. Посмотрев исходный код, он, похоже, напрямую связан с C.dll, поэтому я не знаю, почему он так медленнее. Одна из возможностей заключается в том, что маршалинг строк из native на Java может быть быстрее на Android, чем на С# на Xamarin.
Вот несколько сведений, которые я нашел в другом тесте между собственными решениями Xamarin и Xamarin.Forms(тесты также включают в себя производительность iOS) на двух следующих устройствах:
Samsung Galaxy A7: Версия ОС Android: 6.0 Центральный процессор: Octa-core 1,9 ГГц Cortex-A53 Оперативная память: 3 ГБ Разрешение экрана: 1920 × 1080
iPhone 6s: Версия iOS: 10.3.3 Центральный процессор: двухъядерный 1,84 ГГц Twister ОЗУ: 2 ГБ Разрешение дисплея: 1334 × 750
Сравнение производится по нескольким общим функциям, каждый со своим приложением:
- Basic "Hello World"
- REST API
- JSON Serialization/Deserialization
- Photo Loading
- SQL Database Insert and Get All
Каждый тест повторяется несколько раз, графики показывают средние результаты.
Hello World
API поддержки
Набор тестов, предназначенных для измерения времени, которое требуется, чтобы приложение отправляло запрос через REST API и получало ответ без дальнейшей обработки данных, используя API OpenWeatherMap.
Операции JSON Тесты, выполненные с использованием инфраструктуры Newtonsoft Json.net для сериализации и десериализации объектов JSON во всех приложениях Xamarin. Серийная сериализация и десериализация сериализации Android тестировались с использованием двух библиотек Java: Jackson и GSON.
Выполняются два прогона: первый с нуля и второй с кешированной информацией и операциями
Первый запуск:
(Native iOS JSON Operations убивает эту тестовую битву, а Xamarin присоединяется к ней во втором)
Операции с фотографиями
Сначала загрузите изображения с тремя различными разрешениями:
Resolution – 858×569, Size – 868Kb
Resolution – 2575×1709, Size – 8Mb
Resolution – 4291×2848, Size – 28.9Mb
Что-то казалось неуверенным в результатах Xamarin.Forms для этого теста, поэтому он не включен в график.
Операции SQLite
Проверено две операции:
BulkInsert: Loading rows of data into a database table.
GetAll: Retrieving all data from the database.
С базами данных, имеющими 10 000 записей. Все операции были обработаны внутри устройства.
Xamarin Native (Xamarin.iOS/Xamarin.Android) проявляют себя как довольно хорошие альтернативы родному коду, тогда как Xamarin.Forms во многих случаях кажется медленным, но это может быть действительно хорошим решением для разработки действительно простых приложений быстрее.
Полное тестирование исходит из этого источника:
Спасибо, что дали мне объяснения, чтобы усилить мой ответ, надеюсь, что это поможет немного:)
Производительность - это неопределенное слово, если вы не определяете, что вы подразумеваете под действием производительности, если это простая вычислительная производительность Xamarin может быть быстрее, чем Java, в зависимости от характера вычисления.
Android nativly поставляется с форматами multipe для выполнения кода в:
Совершенно очевидно, что при выполнении кода более естественным будет решение, тем быстрее оно будет. Язык, основанный на времени выполнения, никогда не будет бить язык, который непосредственно запускается на процессоре.
Но, с другой стороны, если вы хотите измерить реальную производительность использования Java, то propbaby будет быстрее, чем Xamarin.
При сравнении Xamarin с обычными старыми Java-приложениями производительность может быть намного быстрее для Xamarin, поскольку она может быть медленнее.
В реальном мире приложения Xamarin, скорее всего, будут медленнее, чем Java-приложения, потому что многие вызовы на базе Android/Java (системные) необходимо делегировать и выполнять во время выполнения Xamarin с помощью так называемых привязок.
Существует несколько различных типов привязок, которые важно знать:
Подробнее о MCW и ACW здесь: https://developer.xamarin.com/guides/cross-platform/application_fundamentals/building_cross_platform_applications/part_1_-_understanding_the_xamarin_mobile_platform/
Привязки с точки зрения производительности очень дорогостоящие. Вызов метода С++ из Java добавляет огромные накладные расходы во время вызова, вызывая метод С++ из С++ во много раз быстрее.
Кто-то выполнил тест производительности, чтобы рассчитать, сколько операций Java в среднем связано с вызовом JNI: Каковы количественные накладные расходы на вызов JNI?
Но не только вызовы JNI являются дорогостоящими, поэтому звонки в MCW и ACW и обратно. Приложения Xamarin реального мира делают много звонков с использованием привязок, и из-за этого реального использования приложения Xamarin может быть (и будет в целом) медленнее обычного старого Java-приложения. Однако в зависимости от того, как было разработано приложение Xamarin, очень вероятно, что пользователь не заметит разницы.
TL;DR/Заключение: Xamarin необходимо использовать привязки al sorts, которые являются дорогостоящими.
Помимо привязок, есть много других факторов, связанных с реализацией реального мира, например: размер двоичного файла, загрузка приложения в память, операции ввода-вывода и многое другое. Сообщение в блоге, которое исследует некоторые из этих вещей, можно найти здесь: https://magenic.com/thinking/mobile-development-platform-performance-part-2-native-cordova-classic-xamarin-xamarin-forms
Это довольно старые тесты, но могут быть релевантными: https://github.com/EgorBo/Xamarin.Android-vs-Java
Арифметический тест
Коллекции, дженерики, настраиваемые типы значений
Работа со строками