Mono准备好迎接黄金时段吗?

时间:2008-08-20 17:57:45

标签: .net open-source mono

有没有人使用过大型或中型项目的开源.NET实现Mono?我想知道它是否适合现实世界的生产环境。它是否稳定,快速,兼容,......足以使用?是否需要花费大量精力将项目移植到Mono运行时,或者它是否真的真正兼容,只需要为Microsoft的运行时获取并运行已编写的代码?

17 个答案:

答案 0 :(得分:402)

有几种情况需要考虑:(a)如果您正在移植现有应用程序并想知道Mono是否足够完成此任务; (b)你开始写一些新的代码了,你想知道Mono是否足够成熟。

对于第一种情况,您可以使用Mono Migration Analyzer tool(Moma)来评估您的应用程序在Mono上运行的程度。如果评估结果显示颜色鲜艳,您应该开始测试和QA并准备发货。

如果您的评估结果显示一个报告突出显示Mono中缺少或显着不同的功能,则必须评估代码是否可以调整,重写或在最坏的情况下,您的应用程序是否可以使用减少的功能。

根据我们根据用户提交的Moma统计数据(这是来自内存),大约50%的应用程序开箱即用,大约25%需要大约一周的工作量(重构,调整)另外15%需要一个严肃承诺重做你的代码块,其余的不值得打扰移植,因为它们与Win32如此紧密相关。在这一点上,要么你从零开始,要么商业决策将推动你的代码可移植,但我们正在谈论几个月的工作(至少从我们的报告中)。

如果您从头开始,情况要简单得多,因为您只会使用Mono中的API。只要您使用支持的堆栈(几乎是.NET 2.0,加上3.5中的所有核心升级,包括LINQ和System.Core,再加上任何Mono跨平台API),您就可以了。

每隔一段时间你就会遇到Mono中的bug或限制,你可能不得不解决它们,但这与其他任何系统没有什么不同。

至于可移植性:ASP.NET应用程序更容易移植,因为它们几乎没有依赖于Win32,你甚至可以使用SQL服务器或其他流行的数据库(Mono有很多捆绑的数据库提供程序)。

Windows.Forms移植有时比较棘手,因为开发人员喜欢逃离.NET沙箱和P / Invoke他们的大脑来配置一些有用的东西,如改变光标闪烁率表示为在WParam中以BCD格式编码的两个贝塞尔点。或者像那样的垃圾。

答案 1 :(得分:65)

它具有相当广泛的覆盖范围,直到.NET 4.0,甚至包括.NET 4.5 API的一些功能,但由于不推荐使用API​​,创建了新的替代方案或者创建了新的替代方案,因此我们选择了一些区域。范围太大。 Mono中没有以下API:

  • Windows Presentation Foundation
  • Windows Workflow Foundation(两个版本都不是)
  • 实体框架
  • WSE1 / WSE2“附加组件”到标准Web服务堆栈

此外,我们的WCF实现仅限于Silverlight支持的内容。

检查特定项目的最简单方法是运行Mono Migration Analyzer (MoMA)。好处是它会通知Mono团队一些问题会阻止你使用Mono(如果有的话),这会让他们优先考虑他们的工作。

我最近在SubSonic上运行MoMA,发现只有一个问题 - Nullable类型的奇怪使用。这是一个很大的代码库,所以那里的报道非常令人印象深刻。

Mono正在several commercial as well as open source products中使用。它在一些大型应用程序中使用,例如Wikipedia and the Mozilla Developer Center,并已用于嵌入式应用程序,如Sansa MP3播放器,并为数千种已发布的游戏提供支持。

在语言层面the Mono compiler is fully compliant with the C# 5.0 language specification

答案 2 :(得分:39)

在桌面方面,如果您承诺使用GTK#,Mono可以很好地工作。 Windows.Forms实现仍然是一个小错误(例如,TrayIcon不起作用)但它已经走了很长的路。此外,GTK#是比Windows Forms更好的工具包。

在网络方面,Mono已经实现了足够的ASP.NET来完美地运行大多数网站。这里遇到的困难是找到一个在apache上安装mod_mono的主机,或者如果你有shell访问你的主机就自己动手。

无论哪种方式,Mono都很棒,而且很稳定。

创建跨平台程序时要记住的关键事项:

  • 使用GTK#而不是Windows.Forms
  • 确保正确填写文件名
  • 使用Path.Separator代替硬编码"\",也可以使用Environment.NewLine代替"\n"
  • 不要对Win32 API使用任何P / Invoked调用。
  • 请勿使用Windows注册表。

答案 3 :(得分:23)

我个人在黄金时段使用Mono。 我运行单处理服务器处理与gd字节的udp / tcp数据处理相关的任务,并且不能更快乐。

有一些特点,最烦人的事情之一是你不能仅仅因为Mono的当前状态而“构建”你的msbuild文件:

  • MonoDevelop(IDE)有一些部分的msbuild支持,但基本上会在任何“REAL”构建版本上超出简单的hello-world(自定义构建任务,动态“属性”,如$(SolutionDir),真正的配置到名称几个死胡同)
  • xbuild哪个应该单声道提供的msbuild-fully-compatible-build-system更加可怕,所以从命令行构建实际上比使用GUI更糟糕的体验,这是一个非常“非正统”的Linux环境联盟状态......

一旦/在让你的东西真正建立起来的过程中,你甚至可能会看到一些更加荒谬的代码:

  • 编译器对某些结构感到厌烦
  • 和某些更高级的/新的.NET类会给你带来意想不到的废话(XLinq是谁?)
  • 一些不成熟的运行时“功能”(3GB堆限制ON x64 ... WTF!)

但是他说,一般来说,事情开始很快,解决方案/解决方法很多

一旦你完成了那些最初的障碍,我的经验是单声道ROCKS,并且每次迭代都会越来越好

我已经让服务器运行单声道,每天处理300GB的数据,有大量的p / invokes,一般说来做很多工作并保持5-6个月的UP,即使是“前沿”单声道。

希望这有帮助。

答案 4 :(得分:21)

接受答案的建议现在有些过时了。

  • Windows窗体的实现现在非常好。 (有关Paint.net的端口,请参阅Paint-Mono,这是一个非常复杂的Windows窗体应用程序。所需要的只是一些P-Invoke和不支持的系统调用的仿真层。)
  • Path.Combine以及Path.Seperator,用于连接路径和文件名。
  • Windows注册表是可以的,只要您只使用它来存储和检索应用程序中的数据(即,您无法从中获取有关Windows的任何信息,因为它基本上是Mono应用程序的注册表)。

答案 5 :(得分:12)

如果你想使用WPF,你运气不佳Mono目前没有计划实施它。

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

答案 6 :(得分:9)

嗯,单声道是伟大的,但据我所知,它是不稳定的。它可以工作,但是当你给单声道处理做一个认真的工作时会出现故障。

TL; DR - 如果您:

,请不要使用单声道
  • 在多线程环境中使用AppDomains(程序集加载\卸载)
  • 无法维持'let-it-fail'模式
  • 在流程运行期间偶尔遇到重载事件

所以,事实。

我们在RHEL5,Ubuntu上使用mono-2.6.7(.net v 3.5),而在我看来,它是由Novell构建的最稳定的版本。它有一个卸载AppDomains(segfaults)的问题,然而,它失败非常罕见,到目前为止,这是可以接受的(由我们)。

好。但是如果你想使用.net 4.0的功能,你必须切换到版本2.10.x或3.x,这就是问题开始的地方。

与2.6.7相比,新版本使用起来是不可接受的。我写了一个简单的压力测试应用程序来测试单声道安装。

就在这里,有使用说明:https://github.com/head-thrash/stress_test_mono

它使用线程池工作线程。工作者将DLL加载到AppDomain并尝试进行一些数学工作。有些工作是多线程的,有些是单一的。几乎所有工作都受CPU约束,尽管从磁盘中读取了一些文件。

结果不是很好。事实上,对于3.0.12版本:

  • sgen GC段错误过程几乎立即进行
  • 单声道与boehm寿命更长(从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 from source):

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逻辑,所以,你应该单声道地远离它们。

BTW,经过测试的程序在Windows机器上运行24小时,在MS .NET 4.5 env中没有任何失败。

所以,最后,我想说 - 谨慎使用mono。它从第一眼开始工作,但随时都很容易失败。你会在开源项目中留下一堆核心转储和主要信念损失。

答案 7 :(得分:5)

正如其他人所建议的那样,现代艺术博物馆是一个很好的工具。目前最大的不兼容性来源是DllImport(或P / Invoke)到Win32库中的应用程序。有些程序集没有实现,但大多数只是Windows,在Linux上真的没用。我认为大多数ASP.NET应用程序都可以在Mono上运行并且修改有限,这是相当安全的。

(披露:我为Mono本身以及在其上运行的书面应用程序做出了贡献。)

答案 8 :(得分:4)

我们一直在将这个项目用于需要在Linux上运行的项目,但重用了我们在Managed C ++中构建的一些.NET库。我对它的成功程度感到非常惊讶。我们的主要可执行文件是用C#编写的,我们可以毫无问题地引用我们的托管C ++二进制文件。 Windows和Linux之间C#代码的唯一区别是RS232串口代码。

我能想到的唯一重大问题发生在一个月前。 Linux版本的内存泄漏在Windows版本中没有出现。在做了一些手动调试之后(Linux上Mono的基本剖析器没有多大帮助),我们能够将问题缩小到特定的代码块。我们最终修补了一个解决方法,但我仍然需要找一些时间回过头来弄清楚泄漏的根本原因是什么。

答案 9 :(得分:4)

在许多情况下,您可以使用现有代码并在Mono上运行它,尤其是在移植ASP.NET应用程序时。

在某些情况下,您可能需要全新的代码段才能使其正常工作。例如,如果您使用System.Windows.Forms,则应用程序将无法正常工作。同样,如果您使用任何Windows特定的代码(例如,注册表访问代码)。但我认为最糟糕的罪犯是UI代码。这在Macintosh系统上尤其糟糕。

答案 10 :(得分:2)

  

你知道Mono 2.0预览版对Windows Forms 2.0的支持有多好吗?

从我玩过它的一点点来看,它似乎相对完整且几乎可用。它在某些地方看起来并不是很正确,但总体上还是有点受欢迎。令我感到惊讶的是,它与我们的一些形式一样有效,但老实说。

答案 11 :(得分:2)

是的,肯定是(如果你小心的话) 我们支持Ra-Ajax中的Mono(在http://ra-ajax.org找到的Ajax库),我们根本没有遇到任何问题。你需要小心一些来自.Net的“最疯狂的东西”,比如WSE等,也可能你现有的一些项目不会100%兼容Mono,但是如果你在开发过程中测试它们的新项目兼容Mono没有问题。通过使用Mono来支持Linux等的收益非常酷;)

我认为支持Mono的秘诀的一大部分是从一开始就使用正确的工具,例如: ActiveRecord,log4net,ra-ajax等......

答案 12 :(得分:2)

对于我们正在构建Mono的应用程序类型,遗憾的是它似乎还没有准备好生产。我们对它的整体印象深刻,并且在Windows和EC2机器上的性能给我们留下了深刻的印象,然而,我们的程序在Windows和Linux上都与垃圾收集错误一致。

错误消息是:“GC中的致命错误:堆部分太多”,这里是以稍微不同的方式链接到遇到问题的其他人:

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

我们在Mono中运行的第一段代码是我们开发的一个简单的编程挑战......代码将大约10mb的数据加载到某些数据结构(例如HashSets)中,然后针对数据运行10次查询。我们运行了100次查询,以便为它们计时并获得平均值。

代码在Windows上的第55个查询周围崩溃。在Linux上它可以工作,但是一旦我们转移到更大的数据集,它也会崩溃。

此代码非常简单,例如将一些数据放入HashSet,然后查询那些HashSets等,所有本地c#,没有任何不安全,没有API调用。在Microsoft CLR上,它永远不会崩溃,并且可以在1000次上运行大量数据集。

我们其中一个人通过电子邮件向Miguel发送电子邮件,其中包含导致问题的代码,但尚无响应。 :(

似乎许多其他人在没有解决方案的情况下遇到了这个问题 - 建议使用不同的GC设置重新编译Mono,但这似乎只会增加崩溃之前的阈值。

答案 13 :(得分:2)

请访问www.plasticscm.com。一切(客户端,服务器,GUI,合并工具)都是用单声道写的。

答案 14 :(得分:1)

我想,如果你有一个带有某些第三方组件的应用程序,你可能会被填充。我怀疑很多供应商会在考虑Mono的情况下开发

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

答案 15 :(得分:1)

它实际上取决于您从.NET框架使用的命名空间和类。我有兴趣将我的一个Windows服务转换为在我的电子邮件服务器上运行,这是Suse,但是我们遇到了几个没有完全实现的API的硬路障。 Mono网站上有一个图表列出了所有类及其完成程度。如果你的申请被覆盖,那就去吧。

与任何其他应用程序一样,当然,在做出全面承诺之前,请进行原型设计和测试。

我们遇到的另一个问题是许可软件:如果您引用其他人的DLL,则无法对埋藏在该程序集中的不兼容性进行编码。

答案 16 :(得分:1)

不,单声道还没准备好开展认真的工作。我使用F#在Windows上编写了一些程序,并在Mono上运行它们。那些程序非常密集地使用磁盘,内存和CPU。我看到单声道库(托管代码)崩溃,本机代码崩溃和虚拟机崩溃。当单声道工作时,程序至少比Windows中的.Net慢两倍,并且使用了更多的内存。为了认真的工作,远离单声道。