O Mono está pronto para o horário nobre?

Alguém já usou o Mono, a implementação .NET de código aberto em um projeto grande ou médio? Eu estou querendo saber se está pronto para o mundo real, ambientes de produção. É estável, rápido, compatível … o suficiente para usar? É preciso muito esforço para portar projetos para o runtime Mono, ou é realmente, realmente compatível o suficiente para executar e executar código já escrito para o runtime da Microsoft?

Há alguns cenários a serem considerados: (a) se você estiver portando um aplicativo existente e se perguntando se o Mono é bom o suficiente para essa tarefa; (b) você está começando a escrever algum novo código, e você quer saber se o Mono está maduro o suficiente.

No primeiro caso, você pode usar a ferramenta Mono Migration Analyzer (Moma) para avaliar o quanto o aplicativo está sendo executado no Mono. Se a avaliação voltar com colors de vôo, você deve começar seus testes e controle de qualidade e prepare-se para enviar.

Se a sua avaliação retornar com um relatório destacando resources que estão ausentes ou que diferem significativamente em sua semântica no Mono, você terá que avaliar se o código pode ser adaptado, reescrito ou, no pior dos casos, se o aplicativo pode funcionar com funcionalidade reduzida.

De acordo com nossas statistics Moma baseadas em envios de usuários (isto é da memory) cerca de 50% dos aplicativos funcionam, cerca de 25% exigem cerca de uma semana de trabalho (refatoração, adaptação) outros 15% exigem um compromisso sério para refazer pedaços de seu código, e o resto não vale a pena incomodar a portabilidade, pois eles são incrivelmente ligados ao Win32. Nesse ponto, você começa do zero ou uma decisão de negócios impulsionará o esforço para tornar seu código portátil, mas estamos falando de meses de trabalho (pelo menos nos relatórios que temos).

Se você está começando do zero, a situação é muito mais simples, porque você só estará usando as APIs que estão presentes no Mono. Contanto que você fique com a pilha suportada (que é praticamente .NET 2.0, mais todas as atualizações principais em 3.5, incluindo LINQ e System.Core, além de qualquer uma das APIs de plataforma cruzada Mono), você estará bem.

De vez em quando, você pode encontrar bugs em Mono ou limitações, e pode ser necessário contorná-los, mas isso não é diferente de qualquer outro sistema.

Quanto à portabilidade: os aplicativos ASP.NET são os mais fáceis de portar, já que eles têm pouca ou nenhuma dependência no Win32 e você pode até mesmo usar o SQL Server ou outros bancos de dados populares (há muitos provedores de database com o Mono).

A portabilidade do Windows.Forms é às vezes mais complicada porque os desenvolvedores gostam de escaping do sandbox do .NET e P / Invoke seus cérebros para configurar coisas tão úteis quanto mudar a taxa de intermitência do cursor expressa como dois pontos bezier codificados no formato BCD em um wParam. Ou algum lixo assim.

Ele tem uma cobertura bastante extensa até o .NET 4.0 e até mesmo inclui alguns resources das APIs do .NET 4.5, mas há algumas áreas que optamos por não implementar, pois as APIs estão sendo substituídas, novas alternativas sendo criadas ou o escopo sendo muito ampla. As seguintes APIs não estão disponíveis no Mono:

  • Windows Presentation Foundation
  • Windows Workflow Foundation (nenhuma das duas versões)
  • Estrutura de entidade
  • Os “complementos” do WSE1 / WSE2 para a pilha padrão de serviços da Web

Além disso, nossa implementação do WCF é limitada ao que o Silverlight oferece suporte.

A maneira mais fácil de verificar seu projeto específico é executar o Mono Migration Analyzer (MoMA) . O benefício é que ele notificará a equipe do Mono sobre questões que impedirão você de usar o Mono (se houver), o que permite priorizar seu trabalho.

Recentemente, executei o MoMA no SubSonic e encontrei apenas um problema – um uso estranho de tipos Nullable. Essa é uma grande base de código, então a cobertura era bem impressionante.

O Mono está em uso ativo em vários produtos comerciais e de código aberto . Ele está em uso em alguns aplicativos grandes, como o Wikipedia e o Mozilla Developer Center , e tem sido usado em aplicativos incorporados, como os MP3 players Sansa, e ativa milhares de jogos publicados.

No nível da linguagem, o compilador Mono é totalmente compatível com a especificação da linguagem C # 5.0 .

No lado da área de trabalho, o Mono funciona muito bem se você se comprometer a usar o GTK #. A implementação do Windows.Forms ainda é um pouco bugs (por exemplo, o TrayIcon não funciona), mas já percorreu um longo caminho. Além disso, o GTK # é um kit de ferramentas melhor que o Windows Forms.

No lado da Web, a Mono implementou o suficiente do ASP.NET para executar a maioria dos sites perfeitamente. A dificuldade aqui é encontrar um host que tenha o mod_mono instalado no apache, ou fazer você mesmo se você tiver access ao shell do seu host.

De qualquer maneira, o Mono é ótimo e estável.

Pontos principais a serem lembrados ao criar um programa de plataforma cruzada:

  • Use GTK # em vez de Windows.Forms
  • Certifique-se de apresentar corretamente seus nomes de arquivos
  • Use Path.Separator vez de hardcoding "\" , use também Environment.NewLine vez de "\n" .
  • Não use chamadas P / Chamada para a API do Win32.
  • Não use o Registro do Windows.

Eu pessoalmente uso Mono em um env prime-time. Eu executo servidores mono lidando com giga-bytes de tarefas relacionadas ao processamento de dados udp / tcp e não poderia estar mais feliz.

Existem peculiaridades, e uma das coisas mais irritantes é que você não pode simplesmente “construir” seus arquivos msbuild devido ao estado atual do Mono:

  • O MonoDevelop (o IDE) tem algum suporte parcial ao msbuild, mas basicamente vai funcionar em qualquer construção “REAL” além de um simples hello-world (tarefas customizadas, propriedades dinâmicas como $ (SolutionDir), configuração real para nomear alguns mortos -endes)
  • O xbuild que deveria ter sido o sistema de build mono-fornecido-msbuild-fully-compatible é ainda mais horrível, então construir a partir da linha de comando é uma experiência pior do que usar a GUI, que é um estado muito “não ortodoxo” do união para ambientes Linux …

Uma vez / durante a obtenção de suas coisas realmente construídas, você pode ver alguns wildernesses mesmo para o código que deve ser apoiado como:

  • o compilador ficando borked em certas construções
  • e certas classs .NET mais avançadas / novas jogando porcaria inesperada em você (XLinq alguém?)
  • alguns “resources” de tempo de execução imaturos (limite de heap de 3 GB ON x64 … WTF!)

mas o palpite disse que, de um modo geral, as coisas começam a funcionar muito rapidamente e as soluções / soluções alternativas são abundantes .

Uma vez que você superou esses obstáculos iniciais, minha experiência é de mono ROCKS, e continua melhorando a cada iteração .

Eu tive servidores rodando com mono, processando 300GB de dados por dia, com toneladas de p / invokes e falando de modo geral fazendo muito trabalho e permanecendo UP por 5-6 meses, mesmo com o mono “edge edge”.

Espero que isto ajude.

As recomendações para a resposta aceita estão um pouco desatualizadas agora.

  • A implementação de formulários do windows é muito boa agora. (Veja Paint-Mono para uma porta do Paint.net que é uma aplicação de formulários do Windows bastante envolvida. Tudo o que era necessário era uma camada de emulação para algumas das chamadas do sistema P-Invoke e não suportadas).
  • Path.Combine, bem como Path.Seperator para juntar caminhos e nomes de arquivos.
  • O Registro do Windows está OK, contanto que você o use apenas para armazenar e recuperar dados de seus aplicativos (ou seja, não é possível obter informações sobre o Windows a partir dele, pois é basicamente um registro para aplicativos Mono).

Se você quiser usar o WPF, está fora de sorte Mono atualmente não tem planos para implementá-lo.

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

Bem, mono é ótimo, mas até onde eu posso ver, é instável. Funciona, mas falha quando você dá ao mono processo um trabalho sério a ser feito.

TL; DR – Não use mono se você:

  • use AppDomains (Assembly Load \ Unload) em ambientes multithread
  • Não é possível sustentar o modelo ‘let-it-fail’
  • Experimente events ocasionais de carga pesada durante a execução do processo

Então, os fatos.

Usamos mono-2.6.7 (.net v 3.5) no RHEL5, Ubuntu e, no meu ponto de vista, é a versão mais estável construída pela Novell. Ele tem um problema com Unloading AppDomains (segfaults), no entanto, ele falha muito raro e isso, de longe, é aceitável (por nós).

OK. Mas se você quiser usar resources do .net 4.0, terá que alternar para as versões 2.10.x ou 3.x, e é aí que os problemas começam.

Comparado com o 2.6.7, novas versões são simplesmente inaceitáveis ​​para serem usadas. Eu escrevi um aplicativo simples de teste de estresse para testar instalações mono.

É aqui, com instruções para usar: https://github.com/head-thrash/stress_test_mono

Ele usa Thread Threads de trabalho do pool. Trabalhador carrega dll para AppDomain e tenta fazer algum trabalho de matemática. Alguns trabalhos são muitos, alguns são simples. Quase todo o trabalho é limitado pela CPU, embora haja algumas leituras de arquivos do disco.

Os resultados não são muito bons. De fato, para a versão 3.0.12:

  • sgen processo de segfaults GC quase que imediatamente
  • mono com boehm vive mais (de 2 a 5 horas), mas eventualmente os segfaults

Como mencionado acima, o sgen gc simplesmente não funciona (mono construído a partir da fonte):

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

Quanto a segfauls boehm – por exemplo (Ubuntu 13.04, mono construído a partir da fonte):

 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 

Ou (RHEL5, mono é tirado do rpm aqui 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 as falhas estão de alguma forma conectadas à lógica AppDomains, portanto, você deve ficar longe delas em mono.

BTW, programa testado funcionou 24 horas na máquina Windows no MS .NET 4.5 env sem qualquer falha.

Então, em conclusão, eu gostaria de dizer – use mono com caucanvas. Funciona desde o primeiro olhar, mas pode falhar facilmente quando quiser. Você ficaria com um monte de lixões e grande perda de fé em projetos de código aberto.

O MoMA é uma ótima ferramenta para isso, como alguém sugeriu. As maiores fonts de incompatibilidade nos dias de hoje são aplicativos que DllImport (ou P / Invoke) em bibliotecas Win32. Alguns assemblies não são implementados, mas a maioria deles são apenas para Windows e realmente não fazem sentido no Linux. Eu acho que é razoavelmente seguro dizer que a maioria dos aplicativos ASP.NET pode rodar no Mono com modificações limitadas.

(Divulgação: Eu contribuí com o próprio Mono, bem como aplicativos escritos que são executados em cima dele.)

Em muitos casos, você pode pegar o código existente e apenas executá-lo no Mono, principalmente se estiver portando um aplicativo ASP.NET.

Em alguns casos, você pode requerer novas seções de código para que funcione. Se você usar o System.Windows.Forms, por exemplo, o aplicativo não funcionará sem modificações. Da mesma forma, se você usar qualquer código específico do Windows (código de access do registro, por exemplo). Mas acho que o pior infrator é o código da interface do usuário. Isso é particularmente ruim em sistemas Macintosh.

Nós temos usado isso para um projeto aqui no trabalho que precisava rodar no Linux, mas reutilizar algumas bibliotecas .NET que construímos no Managed C ++. Eu fiquei muito surpreso com o quão bem isso funcionou. Nosso principal executável está sendo escrito em C # e podemos apenas referenciar nossos binários gerenciados em C ++ sem nenhum problema. A única diferença no código C # entre Windows e Linux é o código da porta serial RS232.

O único grande problema que posso pensar aconteceu há um mês. A compilation do Linux teve um memory leaks que não foi visto na compilation do Windows. Depois de fazer uma debugging manual (os gerenciadores de perfis básicos do Mono no Linux não ajudaram muito), conseguimos restringir o problema a um trecho de código específico. Acabamos corrigindo uma solução alternativa, mas ainda precisamos encontrar algum tempo para voltar e descobrir qual foi a causa raiz do vazamento.

Você sabe o quão bom é o suporte do preview do Mono 2.0 para o Windows Forms 2.0?

Do pouco que eu toquei, parecia relativamente completo e quase utilizável. Ele simplesmente não parecia bem em alguns lugares e ainda é um pouco imprevisível no geral. Surpreendeu-me que funcionasse tão bem quanto com algumas das nossas formas, embora honestamente.

Sim, definitivamente é (se você for cuidadoso) Nós apoiamos o Mono em Ra-Ajax (biblioteca Ajax encontrada em http://ra-ajax.org ) e na maioria das vezes não estamos tendo problemas. Você precisa ter cuidado com algumas das “coisas mais loucas” do .Net como o WSE etc, e provavelmente também alguns de seus projetos existentes não serão 100% compatíveis com o Mono, mas novos projetos se você testá-los durante o desenvolvimento serão principalmente seja compatível sem problemas com o Mono. E o ganho de suportar o Linux etc usando o Mono é muito legal;)

Uma grande parte do segredo de apoiar o Mono, eu acho que é usar as ferramentas certas desde o começo, por exemplo: ActiveRecord, log4net, ra-ajax etc …

Para o tipo de aplicativo que estamos construindo, o Mono infelizmente não parece pronto para produção. Ficamos impressionados com isso, e impressionados com seu desempenho tanto no Windows quanto nas máquinas EC2, no entanto, nosso programa travou consistentemente com erros de garbage collection no Windows e no Linux.

A mensagem de erro é: “erros fatais no GC: muitas seções de heap”, aqui está um link para alguém que está enfrentando o problema de uma maneira um pouco diferente:

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

A primeira parte do código que rodamos no Mono foi um desafio de programação simples que nós desenvolvemos … O código carrega dados de 10mb em algumas estruturas de dados (por exemplo, HashSets), então executa 10 consultas contra os dados. Nós executamos as consultas 100 vezes, a fim de cronometrá-las e obter uma média.

O código caiu em torno da consulta 55 no Windows. No linux funcionou, mas assim que nos mudamos para um conjunto maior de dados, ele também falhava.

Este código é muito simples, por exemplo, colocar alguns dados em HashSets e, em seguida, consultar os HashSets etc, todos c # nativo, nada inseguro, sem chamadas de API. No Microsoft CLR, ele nunca trava e roda em grandes conjuntos de dados 1000 vezes, sem problemas.

Um de nossos caras enviou um e-mail para Miguel e incluiu o código que causou o problema, sem resposta ainda. 🙁

Parece também que muitas outras pessoas encontraram esse problema sem solução – uma solução foi sugerida para recompilar o Mono com diferentes configurações de GC, mas isso parece aumentar o limite antes do qual ele falha.

Basta verificar http://www.plasticscm.com. Tudo (cliente, servidor, GUI, ferramentas de mesclagem) é escrito em mono.

Isso realmente depende dos namespaces e classs que você está usando do .NET framework. Eu tinha interesse em converter um dos meus serviços do Windows para rodar no meu servidor de e-mail, que é o Suse, mas nos deparamos com vários obstáculos difíceis com APIs que não foram completamente implementadas. Há um gráfico em algum lugar no site da Mono que lista todas as classs e seu nível de conclusão. Se o seu aplicativo está coberto, então vá em frente.

Como qualquer outro aplicativo, faça protótipos e testes antes de assumir um compromisso total, é claro.

Outro problema que encontramos é o software licenciado: se você está referenciando a DLL de outra pessoa, você não pode codificar seu caminho em torno de incompatibilidades que estão enterradas naquela assembly.

Eu imagino então se você tem um aplicativo com alguns componentes de terceiros que você pode ser recheado. Eu duvido que muitos fornecedores se desenvolvam com o Mono em mente

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

Não, o mono não está pronto para um trabalho sério. Eu escrevi alguns programas no Windows usando F # e os executei no Mono. Esses programas usavam disco, memory e CPU intensivamente. Eu vi falhas em bibliotecas mono (código gerenciado), falhas em código nativo e falhas na máquina virtual. Quando o mono funcionava, os programas eram pelo menos duas vezes mais lentos do que no .Net no Windows e usavam muito mais memory. Fique longe de mono para um trabalho sério.