Mono готов к прайм-тайм?
Кто-нибудь использовал Mono, реализацию с открытым исходным кодом.NET для крупного или среднего проекта? Мне интересно, готова ли она для реального мира, производственных сред. Это стабильно, быстро, совместимо,... достаточно для использования? Требуется ли много усилий для переноса проектов в среду выполнения Mono, или это действительно достаточно совместимо, чтобы просто взять и запустить уже написанный код для среды выполнения Microsoft?
17 ответов
Есть несколько сценариев, которые следует учитывать: (а) если вы переносите существующее приложение и задаетесь вопросом, достаточно ли Mono для этой задачи; (б) вы начинаете писать какой-то новый код и хотите знать, достаточно ли зрел Mono.
В первом случае вы можете использовать инструмент Mono Migration Analyzer (Moma), чтобы оценить, насколько далеко ваше приложение от запуска в Mono. Если оценка возвращается с полетом, вам следует начать тестирование и контроль качества и подготовиться к отправке.
Если ваша оценка возвращается с отчетом, в котором выделены функции, которые отсутствуют или существенно отличаются по своей семантике в Mono, вам придется оценить, может ли код быть адаптирован, переписан или, в худшем случае, может ли ваше приложение работать с ограниченной функциональностью.
Согласно нашей статистике Moma, основанной на данных пользователей (это из памяти), около 50% приложений работают "из коробки", около 25% требуют около недели работы (рефакторинг, адаптация), еще 15% требуют серьезной приверженности переделывать куски вашего кода, а остальное просто не стоит беспокоить портированием, так как они так невероятно привязаны к Win32. На этом этапе либо вы начинаете с нуля, либо деловое решение приведет к тому, что ваш код будет переносимым, но мы говорим о многомесячной работе (по крайней мере, из наших отчетов).
Если вы начинаете с нуля, ситуация намного проще, потому что вы будете использовать только те API, которые есть в Mono. Пока вы используете поддерживаемый стек (который в значительной степени.NET 2.0, плюс все основные обновления в 3.5, включая LINQ и System.Core, а также любой из кроссплатформенных API Mono), все будет в порядке.
Время от времени вы можете столкнуться с ошибками в Mono или ограничениями, и вам, возможно, придется обходить их, но это ничем не отличается от любой другой системы.
Что касается переносимости: приложения ASP.NET легче переносить, поскольку они практически не зависят от Win32, и вы даже можете использовать SQL-сервер или другие популярные базы данных (существует множество провайдеров баз данных с Mono).
Портирование Windows.Forms иногда бывает сложнее, потому что разработчики предпочитают избегать песочницы.NET и P/Invoke, чтобы настраивать такие полезные вещи, как изменение частоты мигания курсора, выраженной в виде двух точек Безье, закодированных в виде BCD в wParam. Или что-то вроде барахла.
Он имеет довольно обширный охват вплоть до.NET 4.0 и даже включает некоторые функции из API.NET 4.5, но есть несколько областей, которые мы решили не реализовывать из-за того, что API устарели, созданы новые альтернативы или слишком большая область большой. Следующие API не доступны в Mono:
- Windows Presentation Foundation
- Windows Workflow Foundation (ни одна из двух версий)
- Entity Framework
- Дополнения WSE1/WSE2 к стандартному стеку веб-сервисов
Кроме того, наша реализация WCF ограничена тем, что поддерживается Silverlight.
Самый простой способ проверить ваш конкретный проект - запустить Mono Migration Analyzer (MoMA). Преимущество заключается в том, что он будет уведомлять команду Mono о проблемах, которые не позволят вам использовать Mono (если таковые имеются), что позволит им расставить приоритеты в своей работе.
Недавно я запустил MoMA на SubSonic и обнаружил только одну проблему - странное использование типов Nullable. Это большая кодовая база, поэтому охват там был довольно впечатляющим.
Mono активно используется в нескольких коммерческих и открытых продуктах. Он используется в некоторых крупных приложениях, таких как Википедия и Центр разработчиков Mozilla, и используется во встроенных приложениях, таких как MP3-плееры Sansa, и поддерживает тысячи опубликованных игр.
На уровне языка компилятор Mono полностью соответствует спецификации языка C# 5.0.
На настольном ПК Mono отлично работает, если вы берете на себя обязательство использовать GTK#. Реализация Windows.Forms все еще немного глючит (например, TrayIcon не работает), но она прошла долгий путь. Кроме того, GTK# является лучшим инструментарием, чем Windows Forms.
На веб-сайте Mono реализовал достаточно ASP.NET для идеального запуска большинства сайтов. Сложность здесь заключается в том, чтобы найти хост с установленным mod_mono на apache или сделать это самостоятельно, если у вас есть доступ к вашему хосту через оболочку.
В любом случае, Mono великолепен и стабилен.
Основные моменты, которые следует помнить при создании кроссплатформенной программы:
- Используйте GTK # вместо Windows.Forms
- Убедитесь в правильности ввода ваших имен файлов
- использование
Path.Separator
вместо жесткого кодирования"\"
также использоватьEnvironment.NewLine
вместо"\n"
, - Не используйте вызовы P/Invoked для Win32 API.
- Не используйте реестр Windows.
Я лично использую Mono в прайм-тайм env. Я использую моно-серверы, занимающиеся гигабайтами задач обработки данных udp/ tcp, и не мог быть счастливее.
Есть некоторые особенности, и одна из самых раздражающих вещей заключается в том, что вы не можете просто "собрать" ваши файлы msbuild из-за текущего состояния Mono:
- MonoDevelop (IDE) имеет некоторую частичную поддержку msbuild, но в основном будет работать на любой "REAL" сборке conf за пределами простого hello-world (пользовательские задачи сборки, динамические "свойства", такие как $(SolutionDir), реальная конфигурация, чтобы назвать несколько мертвых -концов)
- xbuild, который ДОЛЖЕН быть моно-поставляемой-msbuild-полностью совместимой-build-системой, еще более ужасен, поэтому сборка из командной строки на самом деле хуже, чем при использовании GUI, что является очень "неортодоксальным" состоянием объединение для сред Linux...
Однажды / во время получения ваших вещей фактически СОЗДАННЫХ, вы можете увидеть некоторые глупости даже для кода, который СЛЕДУЕТ поддерживать, например:
- компилятор не справляется с определенными конструкциями
- и некоторые более продвинутые / новые классы.NET бросают в вас неожиданную чушь (XLinq кто-нибудь?)
- некоторые незрелые "особенности" времени выполнения (ограничение кучи 3 ГБ НА x64... WTF!)
но он сказал, что, вообще говоря, вещи начинают работать очень быстро, и решения / обходные пути имеются в изобилии.
После того, как вы преодолели эти начальные препятствия, мой опыт показывает, что моно ROCKS постоянно улучшается с каждой итерацией.
У меня были серверы, работающие с моно, обрабатывающие 300 ГБ данных в день, с тоннами вызовов p/ и, вообще говоря, выполняющими МНОГО работы и работающими в течение 5-6 месяцев, даже с монофоническим "острым краем".
Надеюсь это поможет.
Рекомендации для принятого ответа сейчас немного устарели.
- Реализация оконных форм сейчас довольно хороша. (Смотрите Paint-Mono для порта Paint.net, который является довольно сложным приложением для Windows-форм. Все, что требовалось, это эмуляция слоя для некоторых P-Invoke и неподдерживаемых системных вызовов).
- Path.Combine, а также Path.Seperator для объединения путей и имен файлов.
- Реестр Windows в порядке, если вы используете его только для хранения и извлечения данных из ваших приложений (т. Е. Вы не можете получить от него никакой информации о Windows, поскольку это в основном реестр для приложений Mono).
Если вы хотите использовать WPF, вам не повезло: Mono в настоящее время не планирует его внедрять.
Ну, моно это здорово, но насколько я вижу, оно нестабильно. Это работает, но дает сбой, когда вы даете моно процессу серьезную работу.
TL; DR - не используйте моно, если вы:
- использовать AppDomains (Assembly Load\Unload) в многопоточных средах
- Не может выдержать модель "дай-не-провалиться"
- Случайные события с большой нагрузкой во время выполнения процесса
Итак, факты.
Мы используем mono-2.6.7 (.net v 3.5) на RHEL5, Ubuntu, и, на мой взгляд, это самая стабильная версия, созданная Novell. У него есть проблема с выгрузкой доменов приложений (segfaults), однако, это происходит очень редко, и это, безусловно, приемлемо (для нас).
Хорошо. Но если вы хотите использовать функции.net 4.0, вам нужно переключиться на версии 2.10.x или 3.x, и вот тут начинаются проблемы.
По сравнению с 2.6.7 новые версии просто недопустимы. Я написал простое приложение для стресс-теста для тестирования моно установок.
Это здесь, с инструкциями по использованию: https://github.com/head-thrash/stress_test_mono
Он использует рабочие потоки пула потоков. Работник загружает DLL в AppDomain и пытается выполнить некоторую математическую работу. Некоторые работы многопоточные, некоторые одиночные. Почти вся работа связана с процессором, хотя есть некоторые операции чтения файлов с диска.
Результаты не очень хорошие. Фактически для версии 3.0.12:
- Sgen GC обрабатывает ошибки практически мгновенно
- Моно с Бёмом живет дольше (от 2 до 5 часов), но в итоге сегфолты
Как уже упоминалось выше, sgen gc просто не работает (моно собран из исходного кода):
* Assertion: should not be reached at sgen-scan-object.h:111
Stacktrace:
Native stacktrace:
mono() [0x4ab0ad]
/lib/x86_64-linux-gnu/libpthread.so.0(+0xfcb0) [0x2b61ea830cb0]
/lib/x86_64-linux-gnu/libc.so.6(gsignal+0x35) [0x2b61eaa74425]
/lib/x86_64-linux-gnu/libc.so.6(abort+0x17b) [0x2b61eaa77b8b]
mono() [0x62b49d]
mono() [0x62b5d6]
mono() [0x5d4f84]
mono() [0x5cb0af]
mono() [0x5cb2cc]
mono() [0x5cccfd]
mono() [0x5cd944]
mono() [0x5d12b6]
mono(mono_gc_collect+0x28) [0x5d16f8]
mono(mono_domain_finalize+0x7c) [0x59fb1c]
mono() [0x596ef0]
mono() [0x616f13]
mono() [0x626ee0]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x7e9a) [0x2b61ea828e9a]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x6d) [0x2b61eab31ccd]
Что касается Boehm Segfauls - например (Ubuntu 13.04, моно построен из источника):
mono: mini-amd64.c:492: amd64_patch: Assertion `0' failed.
Stacktrace:
at <unknown> <0xffffffff>
at System.Collections.Generic.Dictionary`2.Init (int,System.Collections.Generic.IEqualityComparer`1<TKey>) [0x00012] in /home/bkmz/my/mono/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:264
at System.Collections.Generic.Dictionary`2..ctor () [0x00006] in /home/bkmz/my/mono/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:222
at System.Security.Cryptography.CryptoConfig/CryptoHandler..ctor (System.Collections.Generic.IDictionary`2<string, System.Type>,System.Collections.Generic.IDictionary`2<string, string>) [0x00014] in /home/bkmz/my/mono/mcs/class/corlib/System.Security.Cryptography/Crypto
Config.cs:582
at System.Security.Cryptography.CryptoConfig.LoadConfig (string,System.Collections.Generic.IDictionary`2<string, System.Type>,System.Collections.Generic.IDictionary`2<string, string>) [0x00013] in /home/bkmz/my/mono/mcs/class/corlib/System.Security.Cryptography/CryptoCo
nfig.cs:473
at System.Security.Cryptography.CryptoConfig.Initialize () [0x00697] in /home/bkmz/my/mono/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs:457
at System.Security.Cryptography.CryptoConfig.CreateFromName (string,object[]) [0x00027] in /home/bkmz/my/mono/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs:495
at System.Security.Cryptography.CryptoConfig.CreateFromName (string) [0x00000] in /home/bkmz/my/mono/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs:484
at System.Security.Cryptography.RandomNumberGenerator.Create (string) [0x00000] in /home/bkmz/my/mono/mcs/class/corlib/System.Security.Cryptography/RandomNumberGenerator.cs:59
at System.Security.Cryptography.RandomNumberGenerator.Create () [0x00000] in /home/bkmz/my/mono/mcs/class/corlib/System.Security.Cryptography/RandomNumberGenerator.cs:53
at System.Guid.NewGuid () [0x0001e] in /home/bkmz/my/mono/mcs/class/corlib/System/Guid.cs:492
Или (RHEL5, моно взят из rpm здесь ftp://ftp.pbone.net/mirror/ftp5.gwdg.de/pub/opensuse/repositories/home%3A/vmas%3A/mono-centos5)
Assertion at mini.c:3783, condition `code' not met
Stacktrace:
at <unknown> <0xffffffff>
at System.IO.StreamReader.ReadBuffer () [0x00012] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.IO/StreamReader.cs:394
at System.IO.StreamReader.Peek () [0x00006] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.IO/StreamReader.cs:429
at Mono.Xml.SmallXmlParser.Peek () [0x00000] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/Mono.Xml/SmallXmlParser.cs:271
at Mono.Xml.SmallXmlParser.Parse (System.IO.TextReader,Mono.Xml.SmallXmlParser/IContentHandler) [0x00020] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/Mono.Xml/SmallXmlParser.cs:346
at System.Security.Cryptography.CryptoConfig.LoadConfig (string,System.Collections.Generic.IDictionary`2<string, System.Type>,System.Collections.Generic.IDictionary`2<string, string>) [0x00021] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Security.Cryptog
raphy/CryptoConfig.cs:475
at System.Security.Cryptography.CryptoConfig.Initialize () [0x00697] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs:457
at System.Security.Cryptography.CryptoConfig.CreateFromName (string,object[]) [0x00027] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs:495
at System.Security.Cryptography.CryptoConfig.CreateFromName (string) [0x00000] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs:484
at System.Security.Cryptography.RandomNumberGenerator.Create (string) [0x00000] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Security.Cryptography/RandomNumberGenerator.cs:59
at System.Security.Cryptography.RandomNumberGenerator.Create () [0x00000] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Security.Cryptography/RandomNumberGenerator.cs:53
at System.Guid.NewGuid () [0x0001e] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System/Guid.cs:483
at System.Runtime.Remoting.RemotingServices.NewUri () [0x00020] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Runtime.Remoting/RemotingServices.cs:356
at System.Runtime.Remoting.RemotingServices.Marshal (System.MarshalByRefObject,string,System.Type) [0x000ba] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Runtime.Remoting/RemotingServices.cs:329
at System.AppDomain.GetMarshalledDomainObjRef () [0x00000] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System/AppDomain.cs:1363
Оба сбоя так или иначе связаны с логикой AppDomains, поэтому вы должны держаться подальше от них в моно.
Кстати, протестированная программа работала 24 часа на Windows-машине в MS .NET 4.5 env без сбоев.
Итак, в заключение я бы хотел сказать - используйте моно с осторожностью. Это работает с первого взгляда, но может легко потерпеть неудачу всякий раз. Вы останетесь с кучей основных дампов и большой потерей веры в проектах с открытым исходным кодом.
MoMA является отличным инструментом для этого, как кто-то предложил. Крупнейшими источниками несовместимости в наши дни являются приложения, которые DllImport (или P/Invoke) в библиотеках Win32. Некоторые сборки не реализованы, но большинство из них предназначены только для Windows и не имеют смысла в Linux. Я думаю, что можно с уверенностью сказать, что большинство приложений ASP.NET могут работать на Mono с ограниченными модификациями.
(Раскрытие информации: я внес свой вклад в сам Mono, а также в написанные приложения, которые работают поверх него.)
Мы использовали его для работающего здесь проекта, который должен был работать в Linux, но повторно использовать некоторые библиотеки.NET, которые мы создали в Managed C++. Я был очень удивлен тем, насколько хорошо это сработало. Наш основной исполняемый файл написан на C#, и мы можем просто ссылаться на наши управляемые двоичные файлы C++ без проблем. Единственная разница в коде C# между Windows и Linux - это код последовательного порта RS232.
Единственная большая проблема, о которой я могу думать, произошла около месяца назад. В сборке Linux произошла утечка памяти, которой не было в сборке Windows. После некоторой ручной отладки (основные профилировщики для Mono в Linux не очень помогли), мы смогли сузить проблему до определенного фрагмента кода. Мы закончили исправление обходного пути, но мне все еще нужно найти время, чтобы вернуться и выяснить, какова была основная причина утечки.
Во многих случаях вы можете взять существующий код и просто запустить его в Mono, особенно если вы переносите приложение ASP.NET.
В некоторых случаях вам может потребоваться совершенно новые разделы кода, чтобы заставить его работать. Например, если вы используете System.Windows.Forms, приложение не будет работать без изменений. Аналогично, если вы используете какой-либо специфичный для Windows код (например, код доступа к реестру). Но я думаю, что худшим нарушителем является код пользовательского интерфейса. Это особенно плохо в системах Macintosh.
Знаете ли вы, насколько хороша предварительная поддержка Mono 2.0 для Windows Forms 2.0?
Судя по тому, что я играл с ним, он казался относительно полным и почти пригодным для использования. В некоторых местах он выглядит не совсем правильно, и в целом он все еще немного поражает. Меня поразило, что это работает так же хорошо, как и с некоторыми из наших форм, хотя и честно.
Для типа приложений, которые мы создаем, к сожалению, Mono не готов к производству. Мы были впечатлены в целом и впечатлены его производительностью как на Windows, так и на машинах EC2, однако наша программа постоянно зависала с ошибками сборки мусора как в Windows, так и в Linux.
Сообщение об ошибке: "Неустранимые ошибки в GC: слишком много разделов кучи", вот ссылка на кого-то, кто испытывает проблему немного по-другому:
http://bugzilla.novell.com/show_bug.cgi?id=435906
Первым фрагментом кода, который мы запустили в Mono, была простая задача программирования, которую мы разработали... Код загружает около 10 МБ данных в некоторые структуры данных (например, HashSets), а затем выполняет 10 запросов к данным. Мы запустили запросы 100 раз, чтобы рассчитать их и получить среднее значение.
Код разбился вокруг 55-го запроса в Windows. В Linux это работало, но как только мы перешли к большему набору данных, он тоже потерпел крах.
Этот код очень прост, например, поместить некоторые данные в HashSets и затем запросить эти HashSets и т. Д., Все нативные C#, ничего небезопасного, никаких вызовов API. На Microsoft CLR он никогда не падает, и работает на огромных наборах данных в 1000 раз просто отлично.
Один из наших парней послал Мигелю письмо по электронной почте и включил код, вызвавший проблему, ответа пока нет.:(
Также кажется, что многие другие люди сталкивались с этой проблемой без решения - было предложено одно решение для перекомпиляции Mono с другими настройками GC, но это просто увеличивает порог, до которого происходит сбой.
Просто проверьте www.plasticscm.com. Все (клиент, сервер, графический интерфейс, инструменты слияния) написано на моно.
Да, это определенно (если вы осторожны). Мы поддерживаем Mono в Ra-Ajax (библиотека Ajax, найденная на http://ra-ajax.org/), и у нас в основном вообще нет проблем. Вы должны быть осторожны с некоторыми "самыми безумными вещами" из.Net, такими как WSE и т. Д., А также, вероятно, некоторые из ваших существующих проектов не будут на 100% совместимы с Mono, но новые проекты, если вы их протестируете во время разработки, будут в основном быть совместимым без проблем с Mono. И выгода от поддержки Linux и т. Д. С помощью Mono - это действительно здорово;)
Большая часть секрета поддержки Mono, я думаю, заключается в том, чтобы с самого начала использовать правильные инструменты, например ActiveRecord, log4net, ra-ajax и т. Д.
Нет, моно не готов к серьезной работе. Я написал несколько программ для Windows с использованием F# и запустил их на Mono. Эти программы довольно интенсивно использовали диск, память и процессор. Я видел сбои в моно библиотеках (управляемый код), сбои в нативном коде и сбои в виртуальной машине. Когда моно работал, программы были как минимум в два раза медленнее, чем в.Net в Windows, и использовали гораздо больше памяти. Держитесь подальше от моно для серьезной работы.
Тогда я представляю, что если у вас есть приложение с какими-то сторонними компонентами, вы можете быть заполнены. Я сомневаюсь, что многие поставщики будут развиваться с учетом Mono
Пример: http://community.devexpress.com/forums/p/55085/185853.aspx
Это действительно зависит от пространств имен и классов, которые вы используете из.NET Framework. Я был заинтересован в преобразовании одной из моих служб Windows для работы на моем почтовом сервере, которой является Suse, но мы столкнулись с несколькими серьезными препятствиями с API, которые не были полностью реализованы. Где-то на сайте Mono есть диаграмма, в которой перечислены все классы и уровень их прохождения. Если ваша заявка покрыта, то пойти на это.
Как и в случае с любым другим приложением, выполняйте прототипирование и тестирование, прежде чем выполнять все обязательства.
Еще одна проблема, с которой мы столкнулись, - это лицензионное программное обеспечение: если вы ссылаетесь на чужую DLL, вы не можете закодировать свой путь несовместимости, скрытой в этой сборке.