单声道准备好了吗?
有没有人使用Mono,一个大型或中型项目的开源.NET实现? 我想知道它是否适合现实世界的生产环境。 它稳定,快速,兼容,…足够使用? 将项目移植到Mono运行时需要花费很多精力,还是真的兼容到只运行已经编写的Microsoft运行时代码?
有几种情况需要考虑:(a)如果你正在移植一个现有的应用程序,并想知道单声道是否足够完成这个任务; (b)你开始写一些新的代码,你想知道单声道是否足够成熟。
对于第一种情况,您可以使用Mono Migration Analyzer工具 (Moma)来评估应用程序在Mono上运行的程度。 如果评估回来了,你应该开始你的testing和质量保证并准备出货。
如果您的评估报告中包含突出显示Mono语义缺失或显着差异的报告,您将需要评估是否可以对代码进行修改,重写或在最糟糕的情况下评估您的应用程序是否可以使用更低的function。
根据我们对用户意见的统计(这是从内存中获得的),大约有50%的应用程序是开箱即用的,大约25%需要大约一周的工作(重构,适应),另外15%需要认真的承诺重做你的代码块,其余的只是不值得打扰移植,因为他们是如此令人难以置信的绑定到Win32。 在这一点上,无论是从零开始,还是业务决策都将推动您的代码的可移植性,但是我们正在谈论几个月的工作(至less从我们的报告中)。
如果你从头开始,情况就简单多了,因为你只能使用Mono中存在的API。 只要你支持堆栈(这是相当多的.NET 2.0,再加上所有的核心升级包括LINQ和System.Core,加上任何的Mono跨平台API),你会没事的。
每过一段时间,你可能会遇到单声道或局限性的错误,你可能需要解决它们,但这与其他系统没有区别。
至于可移植性:ASP.NET应用程序是更容易移植的,因为那些对Win32的依赖性很小,甚至可以使用SQL服务器或其他stream行的数据库(Mono中有大量的捆绑数据库提供者)。
Windows.Forms移植有时候会比较棘手,因为开发人员喜欢逃离.NET沙箱,并且调用他们的大脑去configuration一些有用的东西,比如改变光标闪烁的速率,用wParam中的BCD格式编码的两个贝塞尔点。 或者像那样的垃圾
它具有相当广泛的.NET 4.0的覆盖范围,甚至还包括.NET 4.5 API的一些特性,但是由于API被弃用,新的select被创build或者范围太大,我们select了一些不被实现的区域大。 以下API在Mono中不可用:
- Windows Presentation Foundation
- Windows Workflow Foundation(这两个版本都没有)
- entity framework
- WSE1 / WSE2“附加到”标准Web服务堆栈
另外,我们的WCF实现仅限于Silverlight支持的内容。
检查您的特定项目最简单的方法是运行单一迁移分析器(MoMA) 。 好处是它会通知Mono团队将会阻止你使用Mono(如果有的话),从而让他们优先考虑他们的工作。
我最近在SubSonic上运行了MoMA,发现只有一个问题 – 使用Nullabletypes。 这是一个很大的代码库,所以这里的覆盖面非常棒。
单声道在一些商业和开源产品中都被广泛使用 。 它在一些大型应用程序中使用,如维基百科和Mozilla开发人员中心 ,并已用于Sansa MP3播放器等embedded式应用程序,并支持数千种已发布的游戏。
在语言层面, Mono编译器完全符合C#5.0语言规范 。
在桌面方面,如果您承诺使用GTK#,则Mono会很好。 Windows.Forms的实现仍然是一个小错误(例如,TrayIcon的不工作),但它已经走了很长的路。 除此之外,GTK#比Windows Forms更好一些。
在networking方面,Mono已经实现了足够的ASP.NET来完美地运行大多数网站。 这里的困难是find一个在apache上安装了mod_mono的主机,或者如果你有shell访问主机的权限,就自己动手。
无论哪种方式,单声道是伟大的,稳定的。
创build跨平台程序时要记住的关键事项:
- 使用GTK#代替Windows.Forms
- 确保正确处理您的文件名
- 使用
Path.Separator
而不是硬编码"\"
,也可以使用Environment.NewLine
而不是"\n"
。 - 不要对Win32 API使用任何P / Invoked调用。
- 不要使用Windowsregistry。
我个人在黄金时段使用Mono。 我运行处理千兆字节的udp / tcp数据处理相关任务的单声道服务器,并不能幸福。
有一些特殊之处,而最令人讨厌的事情之一就是,由于Mono的当前状态,你不能“build立”你的msbuild文件:
- MonoDevelop(IDE)有一些部分的msbuild支持,但基本上可以在任何“REAL”构buildconf之外的简单hello-world(自定义构build任务,像$(SolutionDir)这样的dynamic“属性” -ends)
- xbuild 应该是单一提供的msbuild-fully-compatible-build-system更可怕,所以从命令行构build实际上比使用GUI更糟糕的经验,这是一个非常“非传统”的状态联合的Linux环境…
一次/在实际获得你的东西时,你可能会看到一些荒野,甚至对于那些应该被支持的代码:
- 编译器在某些构造上得到了一些东西
- 和某些更高级/新的.NET类抛出你想不到的废话(XLinq的人?)
- 一些不成熟的运行时“function”(3GB堆上限x64 … WTF!)
但是大家都说,一般来说,事情很快就开始了,解决scheme/解决方法也很丰富 。
一旦你完成了最初的障碍,我的经验是单声道的ROCKS,每一次迭代都会越来越好 。
我已经有服务器运行单声道,每天处理300GB的数据,大量的p /调用,一般来说,做很多工作,并保持5-6个月,即使是“stream血的边缘”单声道。
希望这可以帮助。
接受的答案的build议现在有点过时了。
- Windows窗体的实现现在是相当不错的。 (请参阅Paint-Mono获取Paint.net的一个端口,这是一个非常复杂的Windows窗体应用程序,所需要的只是某些P-Invoke和不支持的系统调用的仿真层)。
- Path.Combine以及Path.Seperator来joinpath和文件名。
- Windowsregistry是好的,只要你只是用它来存储和检索你的应用程序的数据(即你不能从它得到有关Windows的任何信息,因为它基本上是一个单声道应用程序的registry)。
如果你想使用WPF,你会很失败。目前Mono没有实现它的计划。
那么,单声道是伟大的,但据我所知,它是不稳定的。 它是有效的,但是当你给单声道进程做一个认真的工作时就会出错。
TL; DR – 不要使用单声道,如果你:
- 在multithreading环境中使用AppDomains(Assembly Load \ Unload)
- 不能维持“让它失败”的模式
- 在运行过程中偶尔遇到重负载事件
所以,事实。
我们在RHEL5,Ubuntu上使用mono-2.6.7(.net v 3.5),而且我认为这是Novell最稳定的版本。 它有卸载AppDomain(segfaults)的问题,但是,它是非常罕见的,到目前为止,这是可以接受的(由我们)。
好的。 但是如果你想使用.net 4.0的特性,你必须切换到2.10.x或者3.x版本,这就是问题的出发点。
与2.6.7相比,新版本仅仅是不可接受的。 我写了一个简单的压力testing应用程序testing单声道安装。
这是在这里,使用说明: https : //github.com/head-thrash/stress_test_mono
它使用线程池工作线程。 工作者加载DLL到AppDomain并尝试做一些math工作。 有些工作是multithreading的,有些是单一的。 几乎所有的工作都是CPU绑定的,虽然有一些从磁盘读取文件。
结果不是很好。 实际上,对于3.0.12版本:
- sgen GC segfaults进程几乎立即
- 单声道与勃姆寿命更长(从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
两种故障都以某种方式连接到AppDomain逻辑,因此,您应该远离单声道。
BTW,经过testing的程序在MS .NET 4.5 env的Windows机器上工作24小时,没有任何失败。
所以,最后,我想说 – 谨慎使用mono。 它从第一眼看起来很有效,但每次都很容易失败。 在开源项目中,你会留下一堆核心转储和重大信心损失。
正如其他人所build议的,MoMA是一个很好的工具。 这些日子最大的不兼容的来源是DllImport(或P / Invoke)到Win32库中的应用程序。 一些程序集没有实现,但是大多数程序集都是Windows,而且在Linux上是没有意义的。 我认为这是相当安全的说,大多数ASP.NET应用程序可以运行在有限的修改单声道。
(披露:我已经为Mono本身做出了贡献,以及在其上运行的书面应用程序。)
在许多情况下,您可以使用现有的代码并在Mono上运行它,特别是在移植ASP.NET应用程序时。
在某些情况下,您可能需要全新的代码才能使其工作。 例如,如果您使用System.Windows.Forms,则该应用程序将无法修改。 同样,如果您使用任何特定于Windows的代码(例如registry访问代码)。 但我认为最坏的罪犯是UI代码。 这在Macintosh系统上尤其糟糕。
我们一直在使用它来做一个需要在Linux上运行的项目,但重用我们在Managed C ++中构build的一些.NET库。 对于它的成效如何,我感到非常惊讶。 我们的主要可执行文件是用C#编写的,我们只需引用我们的托pipeC ++二进制文件即可。 Windows和Linux之间的C#代码的唯一区别是RS232串口代码。
我能想到的唯一的大问题是一个月前发生的。 Linux构build有内存泄漏,在Windows版本上没有看到。 在做了一些手动debugging之后(Linux上Mono的基本分析器没有多大帮助),我们能够将问题缩小到特定的代码块。 我们最终修补了一个解决方法,但是我仍然需要找出一些时间去找出泄漏的根源是什么。
你知道Mono 2.0预览版支持Windows Forms 2.0吗?
从我玩过的一点点,它似乎相对完整,几乎可用。 它在一些地方看起来不太合适,总体上还是有点失误。 令我惊讶的是,尽pipe诚实地说,它和我们的一些表格一样有效。
是的,它肯定是(如果你小心),我们支持单Ra-Ajax(Ajax库在http://ra-ajax.orgfind),我们大多没有任何问题。; 你需要小心一些来自.Net等“最疯狂的东西”,像WSE等,也可能相当一部分现有的项目不会是100%单声道兼容,但如果你在开发过程中testing它们的新项目将主要与Mono没有问题兼容。 而通过使用Mono来支持Linux等的收益确实很酷;)
支持单声道的大部分秘密我认为是从一开始就使用正确的工具,例如ActiveRecord,log4net,ra-ajax等…
对于我们正在build造Mono的应用程序types,不幸的是似乎还没有准备好生产。 我们对它的整体印象深刻,并且在Windows和EC2机器上的性能印象深刻,但是,我们的程序在Windows和Linux上都一致地崩溃了垃圾收集错误。
错误信息是:“GC中的致命错误:太多的堆段”,这里是一个链接到其他人以一种稍微不同的方式遇到问题:
http://bugzilla.novell.com/show_bug.cgi?id=435906
我们在Mono中运行的第一段代码是我们开发的一个简单的编程挑战…代码将大约10MB数据加载到一些数据结构(例如HashSets)中,然后对数据运行10个查询。 我们运行查询100次,以计时并获得平均值。
该代码在Windows上的第55个查询周围坠毁。 在Linux上它工作,但只要我们移动到一个更大的数据集,它也会崩溃。
这段代码非常简单,例如把一些数据放到HashSets中,然后查询那些HashSets等,所有原生的C#,没有不安全的,没有API调用。 在微软的CLR上,它永远不会崩溃,并且可以运行在1000s以上的庞大数据集上。
我们的一个人给Miguel发了邮件,其中包含了导致问题的代码,但没有回应。 🙁
也似乎很多其他人遇到这个问题没有解决scheme – 一个解决scheme已经build议重新编译单声道不同的GC设置,但似乎增加了之前,它崩溃的门槛。
只要检查www.plasticscm.com。 所有东西(客户端,服务器,GUI,合并工具)都是用单声道写的。
它真的取决于你在.NET框架中使用的命名空间和类。 我有兴趣将我的一个Windows服务转换到我的电子邮件服务器(Suse)上运行,但是我们遇到了几个硬性障碍,其中API还没有完全实现。 Mono网站上有一张图表,列出了所有的课程及其完成程度。 如果你的应用程序被覆盖,那就去做吧。
像任何其他应用程序一样,在做出完整的承诺之前进行原型devise和testing,当然。
我们遇到的另一个问题是许可软件:如果您引用了其他人的DLL,那么您无法为掩盖在该程序集中的不兼容问题编码。
我会想象,如果你有一些第三方组件的应用程序,你可能会被塞满。 我怀疑很多厂商会考虑Mono
例如: http : //community.devexpress.com/forums/p/55085/185853.aspx
不,单声道没有准备好进行认真的工作。 我使用F#在Windows上编写了几个程序,并在Mono上运行它们。 那些程序使用磁盘,内存和CPU相当密集。 我看到单声道库(托pipe代码)崩溃,崩溃在本机代码和虚拟机崩溃。 单声道工作时,程序至less比.Net在Windows中慢两倍,并使用更多的内存。 远离单声道严肃的工作。