¿Mono está listo para el horario de máxima audiencia?

¿Alguien ha usado Mono, la implementación de .NET de código abierto en un proyecto grande o mediano? Me pregunto si está listo para el mundo real, entornos de producción. ¿Es estable, rápido, compatible, … suficiente para usar? ¿Se requiere mucho esfuerzo para portar proyectos al tiempo de ejecución Mono, o es realmente, realmente lo suficientemente compatible como para tomar y ejecutar el código ya escrito para el tiempo de ejecución de Microsoft?

Hay un par de escenarios a considerar: (a) si está portando una aplicación existente y se pregunta si Mono es lo suficientemente bueno para esta tarea; (b) está empezando a escribir un código nuevo, y desea saber si Mono es lo suficientemente maduro.

Para el primer caso, puede usar la herramienta Mono Migration Analyzer (Moma) para evaluar qué tan lejos se ejecuta su aplicación en Mono. Si la evaluación vuelve con éxito, debe comenzar sus pruebas y control de calidad y prepararse para el envío.

Si su evaluación regresa con un informe que destaca características que faltan o que difieren significativamente en su semántica en Mono, deberá evaluar si el código puede adaptarse, reescribirse o, en el peor de los casos, si su aplicación puede funcionar con funcionalidad reducida.

De acuerdo con nuestras estadísticas de Moma basadas en presentaciones de usuarios (esto es de memoria) aproximadamente el 50% de las aplicaciones funcionan de la caja, alrededor del 25% requiere aproximadamente una semana de trabajo (refactorización, adaptación) otro 15% requiere un compromiso serio para rehace trozos de tu código, y el rest simplemente no vale la pena molestar porting ya que están tan increíblemente ligados a Win32. En ese punto, ya sea que empiece desde cero, o una decisión comercial impulsará el esfuerzo para hacer que su código sea portátil, pero estamos hablando de meses de trabajo (al menos de los informes que tenemos).

Si está empezando desde cero, la situación es mucho más simple, porque solo usará las API que están presentes en Mono. Mientras permanezcas con la stack admitida (que es prácticamente .NET 2.0, más todas las actualizaciones principales en 3.5, incluyendo LINQ y System.Core, más cualquiera de las API Mono multiplataforma) estarás bien.

De vez en cuando, puede encontrar errores en Mono o limitaciones, y es posible que tenga que trabajar con ellos, pero eso no es diferente de cualquier otro sistema.

En cuanto a la portabilidad: las aplicaciones ASP.NET son las más fáciles de transportar, ya que esas tienen poca o ninguna dependencia en Win32 e incluso puede usar SQL Server u otras bases de datos populares (hay muchos proveedores de bases de datos integrados con Mono).

La migración de Windows.Forms es a veces más complicada porque a los desarrolladores les gusta escapar del sandbox de .NET y P / Invocar sus sesos para configurar cosas tan útiles como cambiar la velocidad de parpadeo del cursor expresada como dos puntos bezier codificados en formato BCD en un wParam. O algo así como basura.

Tiene una cobertura bastante amplia hasta .NET 4.0 e incluso incluye algunas características de .NET 4.5 API, pero hay algunas áreas que hemos elegido no implementar debido a que las API están en desuso, se están creando nuevas alternativas o el scope es demasiado grande. Las siguientes API no están disponibles en Mono:

  • Fundación de presentación de Windows
  • Windows Workflow Foundation (ninguna de las dos versiones)
  • Marco de la entidad
  • Los “complementos” WSE1 / WSE2 a la stack de servicios web estándar

Además, nuestra implementación de WCF está limitada a lo que Silverlight apoyó.

La forma más fácil de verificar su proyecto específico es ejecutar Mono Migration Analyzer (MoMA) . El beneficio es que notificará al equipo de Mono los problemas que le impedirán usar Mono (si corresponde), lo que les permite priorizar su trabajo.

Recientemente ejecuté MoMA en SubSonic y encontré solo un problema: un uso extraño de los tipos Nullable. Esa es una gran base de código, por lo que la cobertura allí fue bastante impresionante.

Mono está en uso activo en varios productos comerciales y de código abierto . Está en uso en algunas aplicaciones de gran tamaño, como Wikipedia y el Mozilla Developer Center , y se ha utilizado en aplicaciones integradas, como los reproductores de MP3 Sansa y potencia miles de juegos publicados.

En el nivel del lenguaje, el comstackdor Mono cumple totalmente con la especificación del lenguaje C # 5.0 .

En el lado del escritorio, Mono funciona muy bien si te comprometes a usar GTK #. La implementación de Windows.Forms sigue siendo un poco problemática (por ejemplo, TrayIcon no funciona) pero ha recorrido un largo camino. Además, GTK # es un juego de herramientas mejor que Windows Forms como es.

En el lado web, Mono ha implementado suficiente ASP.NET para ejecutar la mayoría de los sitios a la perfección. La dificultad aquí es encontrar un host que tenga mod_mono instalado en apache, o hacerlo usted mismo si tiene acceso de shell a su host.

De cualquier manera, Mono es genial y estable.

Cosas clave para recordar al crear un progtwig multiplataforma:

  • Use GTK # en lugar de Windows.Forms
  • Asegúrese de archivar correctamente sus nombres de archivo
  • Use Path.Separator lugar de hardcoding "\" , también use Environment.NewLine lugar de "\n" .
  • No use ninguna P / Llamadas invocadas a la API de Win32.
  • No use el Registro de Windows.

Yo personalmente uso Mono en un env de horario estelar. Ejecuto servidores mono que se ocupan de giga-bytes de tareas relacionadas con el procesamiento de datos udp / tcp y no podría estar más feliz.

Hay peculiaridades, y una de las cosas más molestas es que no puedes simplemente “construir” tus archivos msbuild debido al estado actual de Mono:

  • MonoDevelop (el IDE) tiene un poco de soporte parcial de msbuild, pero básicamente funcionará en cualquier versión de comstackción “REAL” más allá de un simple hello-world (tareas de comstackción personalizadas, “propiedades” dinámicas como $ (SolutionDir), configuración real para nombrar unos pocos muertos -fines)
  • xbuild, que DEBERÍA haber sido el sistema de comstackción monocompletado, totalmente compatible, es aún más horrible, por lo que construir desde la línea de comandos es en realidad una peor experiencia que usar la GUI, que es un estado muy “poco ortodoxo” de la unión para entornos Linux …

Una vez / Durante el proceso de CONSTRUIR tu material, es posible que veas algunas áreas silvestres incluso para código que DEBE ser compatible como:

  • el comstackdor se pone loco en ciertos constructos
  • y ciertas clases de .NET más avanzadas / nuevas lanzando basura no esperada hacia ti (¿Alguien más con XLinq?)
  • algunas “características” de tiempo de ejecución inmaduras (límite de montón de 3 GB ON x64 … WTF)

pero Waving dijo que, en general, las cosas empiezan a funcionar muy rápidamente, y las soluciones / soluciones son abundantes .

Una vez que haya superado esos obstáculos iniciales, mi experiencia es esa ROCKS mono, y sigue mejorando con cada iteración .

He tenido servidores que ejecutan con mono, procesan 300GB de datos por día, con toneladas de p / invocaciones y, en términos generales, hacen MUCHO trabajo y permanecen ARRIBA durante 5-6 meses, incluso con el mono “sangrando”.

Espero que esto ayude.

Las recomendaciones para la respuesta aceptada están un poco desactualizadas ahora.

  • La implementación de las formas de Windows es bastante buena ahora. (Ver Paint-Mono para un puerto de Paint.net que es una aplicación de formularios de Windows bastante complicada. Todo lo que se requería era una capa de emulación para algunas de las llamadas al sistema P-Invoke y no compatibles).
  • Path.Combine así como Path.Seperator para unir rutas y nombres de archivo.
  • El Registro de Windows está bien, siempre que solo lo utilice para almacenar y recuperar datos de sus aplicaciones (es decir, no puede obtener ninguna información sobre Windows, ya que básicamente es un registro para aplicaciones Mono).

Si quiere usar WPF, no tiene suerte. Mono actualmente no tiene planes de implementarlo.

http://www.mono-project.com/WPF

Bueno, mono es genial, pero por lo que puedo ver, es inestable. Funciona, pero fallas cuando le das a mono process un trabajo serio para hacer.

TL; DR – No use mono si usted:

  • utilizar AppDomains (Assembly Load \ Unload) en entornos multiproceso
  • No se puede sostener el modelo ‘let-it-fail’
  • Experimenta eventos ocasionales de carga pesada durante el proceso

Entonces, los hechos.

Usamos mono-2.6.7 (.net v 3.5) en RHEL5, Ubuntu, y, desde mi punto de vista, es la versión más estable construida por Novell. Tiene un problema con la descarga de AppDomains (segfaults), sin embargo, falla muy poco y esto, de lejos, es aceptable (por nosotros).

Bueno. Pero si desea usar las características de .net 4.0, debe cambiar a las versiones 2.10.xo 3.x, y ahí es donde comienzan los problemas.

En comparación con 2.6.7, las nuevas versiones son simplemente inaceptables para ser utilizadas. Escribí una aplicación de prueba de estrés simple para probar instalaciones mono.

Está aquí, con instrucciones de uso: https://github.com/head-thrash/stress_test_mono

Utiliza Thread Pool Worker Threads. Worker carga dll a AppDomain e intenta hacer un poco de trabajo matemático. Parte del trabajo tiene muchos hilos, algunos es único. Casi todo el trabajo está vinculado a la CPU, aunque hay algunas lecturas de archivos del disco.

Los resultados no son muy buenos. De hecho, para la versión 3.0.12:

  • sgen GC segfaults proceso casi de inmediato
  • mono con boehm vive más tiempo (de 2 a 5 horas), pero segfaults finalmente

Como se mencionó anteriormente, sgen gc simplemente no funciona (mono construido a partir de la fuente):

 * 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] 

En cuanto a boehm segfauls, por ejemplo (Ubuntu 13.04, mono construido a partir de la fuente):

 mono: mini-amd64.c:492: amd64_patch: Assertion `0' failed. Stacktrace: at  <0xffffffff> at System.Collections.Generic.Dictionary`2.Init (int,System.Collections.Generic.IEqualityComparer`1) [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,System.Collections.Generic.IDictionary`2) [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,System.Collections.Generic.IDictionary`2) [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 

O bien (RHEL5, mono está tomado de rpm aquí 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  <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,System.Collections.Generic.IDictionary`2) [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 

Ambas fallas están de alguna manera conectadas a la lógica de AppDomains, por lo tanto, debe mantenerse alejado de ellas en mono.

Por cierto, el progtwig probado trabajó 24 horas en la máquina con Windows en MS .NET 4.5 env sin ningún error.

Entonces, en conclusión, me gustaría decir: usa mono con precaución. Funciona desde el primer vistazo, pero puede fallar fácilmente siempre. Te quedarían un montón de vertederos principales y una gran pérdida de fe en proyectos de código abierto.

El MoMA es una gran herramienta para esto, como sugirió alguien más. Las principales fonts de incompatibilidad actualmente son las aplicaciones que DllImport (o P / Invoke) en las bibliotecas de Win32. Algunos ensamblados no están implementados, pero la mayoría de ellos son solo de Windows y realmente no tienen sentido en Linux. Creo que es bastante seguro decir que la mayoría de las aplicaciones ASP.NET pueden ejecutarse en Mono con modificaciones limitadas.

(Divulgación: he contribuido a la propia Mono, así como a las aplicaciones escritas que se ejecutan en la parte superior).

En muchos casos, puede tomar el código existente y simplemente ejecutarlo en Mono, particularmente si está portando una aplicación ASP.NET.

En algunos casos, puede requerir secciones de código completamente nuevas para que funcione. Si usa System.Windows.Forms, por ejemplo, la aplicación no funcionará sin modificaciones. Del mismo modo, si utiliza cualquier código específico de Windows (código de acceso de registro, por ejemplo). Pero creo que el peor ofensor es el código de UI. Eso es particularmente malo en los sistemas Macintosh.

Lo hemos estado usando para un proyecto aquí en el trabajo que necesitaba ejecutarse en Linux pero reutilizando algunas bibliotecas .NET que creamos en Managed C ++. Me sorprendió mucho lo bien que funcionó. Nuestro ejecutable principal se está escribiendo en C # y solo podemos hacer referencia a nuestros binarios de C ++ administrados sin problemas. La única diferencia en el código C # entre Windows y Linux es el código de puerto serie RS232.

El único gran problema en el que puedo pensar sucedió hace un mes. La versión de Linux tenía una pérdida de memoria que no se veía en la comstackción de Windows. Después de realizar una depuración manual (los perfiladores básicos para Mono en Linux no ayudaron mucho), pudimos reducir el problema a un fragmento específico de código. Terminamos parcheando una solución, pero aún necesito encontrar algo de tiempo para volver y descubrir cuál fue la causa raíz de la fuga.

¿Sabe lo bueno que es el soporte de vista previa de Mono 2.0 para Windows Forms 2.0?

Por el poco que jugué, parecía relativamente completo y casi utilizable. Simplemente no se veía bien en algunos lugares y todavía es un poco impredecible. Me sorprendió que funcionara tan bien como lo hizo con algunas de nuestras formas, aunque honestamente.

Sí, definitivamente lo es (si eres cuidadoso). Apoyamos a Mono en Ra-Ajax (la biblioteca de Ajax se encuentra en http://ra-ajax.org ) y, en general, no tenemos ningún problema. Debe tener cuidado con algunas de las “cosas más locos” de .Net como WSE, etc. y probablemente algunos de sus proyectos existentes no serán 100% compatibles con Mono, pero los nuevos proyectos si los prueba durante el desarrollo serán en su mayoría ser compatible sin problemas con Mono. Y la ganancia de soportar Linux, etc. mediante el uso de Mono es realmente genial;)

Una gran parte del secreto de apoyar Mono, creo, es utilizar las herramientas correctas desde el principio, por ejemplo, ActiveRecord, log4net, ra-ajax, etc.

Para el tipo de aplicación que estamos creando, Mono lamentablemente no parece estar listo para producción. Estamos impresionados con esto en general, e impresionado con su rendimiento tanto en Windows como en máquinas EC2, sin embargo, nuestro progtwig se estrelló de manera consistente con los errores de recolección de basura tanto en Windows como en Linux.

El mensaje de error es: “errores fatales en GC: demasiadas secciones de montón”, aquí hay un enlace a otra persona que experimenta el problema de una manera ligeramente diferente:

http://bugzilla.novell.com/show_bug.cgi?id=435906

La primera pieza de código que ejecutamos en Mono era un simple desafío de progtwigción que habíamos desarrollado … El código carga aproximadamente 10 MB de datos en algunas estructuras de datos (por ejemplo, HashSets), luego ejecuta 10 consultas contra los datos. Corrimos las consultas 100 veces para cronometrarlas y obtener un promedio.

El código se colgó alrededor de la consulta 55 en Windows. En Linux funcionó, pero tan pronto como nos moviéramos a un conjunto de datos más grande, se bloqueaba también.

Este código es muy simple, por ejemplo, poner algunos datos en HashSets y luego consultar esos HashSets, etc., todos c # nativos, nada inseguro, no hay llamadas API. En el CLR de Microsoft, nunca falla, y se ejecuta en enormes conjuntos de datos mil veces bien.

Uno de nuestros muchachos le envió un correo electrónico a Miguel e incluyó el código que causó el problema, sin respuesta aún. 🙁

También parece que muchas otras personas han encontrado este problema sin solución: se ha sugerido una solución para recomstackr Mono con diferentes configuraciones de GC, pero eso solo parece boost el umbral antes de que se bloquee.

Solo revisa http://www.plasticscm.com. Todo (cliente, servidor, GUI, herramientas de fusión) está escrito en mono.

Realmente depende de los espacios de nombres y las clases que está utilizando desde .NET Framework. Tenía interés en convertir uno de mis servicios de Windows para ejecutarlo en mi servidor de correo electrónico, que es Suse, pero nos topamos con varios obstáculos con API que no se habían implementado por completo. Hay un gráfico en el sitio web de Mono que enumera todas las clases y su nivel de finalización. Si su aplicación está cubierta, entonces vaya por ella.

Al igual que cualquier otra aplicación, realice prototipos y pruebas antes de comprometerse por completo, por supuesto.

Otro problema con el que nos encontramos es el software con licencia: si hace referencia a la DLL de otra persona, no puede codificar las incompatibilidades que están ocultas en ese ensamblaje.

Me imagino que si tiene una aplicación con algunos componentes de terceros, puede ser rellenado. Dudo que muchos vendedores desarrollarán con Mono en mente

Ejemplo: http://community.devexpress.com/forums/p/55085/185853.aspx

No, mono no está listo para un trabajo serio. Escribí algunos progtwigs en Windows usando F # y los ejecuté en Mono. Esos progtwigs usaron disco, memoria y CPU bastante intensivamente. Vi lockings en bibliotecas mono (código administrado), lockings en el código nativo y lockings en la máquina virtual. Cuando mono funcionaba, los progtwigs eran al menos dos veces más lentos que en .Net en Windows y usaba mucha más memoria. Manténgase alejado de mono para el trabajo serio.