MonoずMS.NETの違いに぀いお話したしょう





.NETのクロスプラットフォヌム開発は、日々たすたす珟実的になっおいたす。 そしお、最近の公匏のLinux / MacOSサポヌトの発衚埌、幞せな未来は少し近くなりたした。 ゜ヌスコヌドは珟圚MITの䞋にあるため、䞊の図は以前の関連性を倱っおいたす。 ただし、クロスプラットフォヌムの.NETアプリケヌションは長期間䜜成できたす。Monoはこれを支揎したす。 しかし、コミュニティでの圌に察する態床はかなりあいたいです。 「モノは愚かで、すべおが3倍遅くなる」や「モノの䞋では䜕も正垞に起動しない」などの蚀葉をよく耳にしたす。 さらに、これらの人々から特定の事実を聞くこずは非垞にたれです。 質問「䜕が本圓に愚かですか」たたは「䜕が正確に機胜したせんか」それらをst迷に陥れたす。 すべおではありたせん建蚭的な議論が可胜なものもありたすが、ほずんどです。 ほずんどの堎合、inする答えは「はい、䜕も機胜したせん」の粟神で始たりたす。 そしお、それが機胜する堎合、非垞に遅いです」 䌚話の終わりに、Monoでの最埌の各マシンコマンドは数倍遅くなり、゜ヌスコヌドの半分にthrow new Exception()



です。



この投皿では、少し経隓を共有したいず思いたす。 少し前に、 PassportVision補品 Habréでの発衚 をLinuxに移怍したした。 かなり正垞に機胜しおいるず蚀えたす。 はい、Microsoftの埓来の.NET以降-MS.NET䞊のWindowsよりも少し遅いです。 しかし、それは非垞に安定しお機胜し、パフォヌマンスの䜎䞋は根本的なものではありたせん。 同時に、圓瀟の補品は非垞に倧きく、゚ンタヌプラむズのカテゎリヌに分類され、C/.NET機胜を最倧限に掻甚しおいたす。 したがっお、.NET甚の倧芏暡なサヌバヌアプリケヌションを取埗するのは珟実的です-芁望がありたす。 たた、Monoで䜕かを曞いおいるさたざたな開発者ず話す機䌚がありたした-䞻に成功した物語です。



しかし、なぜモノに察しおそれほど吊定的なのですか 問題は、人々がランタむムの違いを本圓に理解したくないずいうこずだず思いたす。 Mono 2.4でLinux甚の.NETアプリケヌションを起動したが、すぐには起動したせんでした。぀たり、Monoは完党に悪いので、䜿甚したせん。 そしお最埌に、唯䞀の方法は非難するこずであり、その実装はMS.NETずはわずかに異なりたす。 新しいMonoバヌゞョンは2ヶ月に1回リリヌスされ、実装は長い間修正されおいたすが、人々は詳现を理解するこずを望たず、貧しいMonoを歩き続け、倧切にし続けおいたす。



今日は、ランタむムが異なる堎合の䟋をいく぀か瀺したす。 もちろん、すべおの違いを持ち出すこずはできたせん-あなたはそれに぀いお本党䜓を曞くこずができたす。 はい。たた、非垞にクヌルな問題を補品コヌドから匕き出すこずもできたせん。゜フトりェアアヌキテクチャのコンテキストからそれらを分離しお、理解しやすい小さなコヌドの圢にするこずは非垞に困難です。 今日の私の仕事は、MonoずMS.NETの違いを䌝えるこずです。 これが初心者のMonoプログラマヌが、「Mono dumb」ずいう蚀葉を振り返るのではなく、発生する問題をより広く芋お察凊するのに圹立぀こずを願っおいたす。



䟋1.異なるバヌゞョンのコンパむラヌ



非垞に簡単な䟋から始めたしょう。 Cプログラムがあり、それをコンパむルしたいずしたす。 知っおいるように、暙準コンパむラは単にCコヌドを察応するILコヌドに倉換し、アセンブリの圢匏で実行したす。 さらに、翻蚳プロセスには特に巧劙な最適化が含たれおいたせん。JITが最適化を担圓しおいるためです。 翻蚳は非垞に簡単であり、経隓豊富な.NET開発者は倚くの堎合、どのようなILコマンドが発生するかを把握できたす。 しかし、䜕らかの理由で、倚くの開発者はこのプロセスが明確であるこずを確信しおいたす。 「゜ヌスプログラムをILにマップする方法はたさに1぀である」ずいうこずを蚌明しようず、かなり熱烈な議論がいく぀かありたした。 通垞、人々は「仕様がありたす」ずいう玠晎らしい議論でこれを動機付けたす。 仕様では倚くの有甚なこずが述べられおいるこずを保蚌したいのですが、任意の番組を攟送するための唯䞀のオプションに぀いおは䜕も蚀われおいたせん。 さらに、コンパむラのバヌゞョンが異なるず、翻蚳ロゞックが異なる堎合がありたす。 これを説明する非垞に簡単な䟋を取り䞊げたした。 次のコヌドを怜蚎しおください。



 var numbers = new int[] { 1, 2, 3 };
      
      





Mono 2.10+およびMS.NETでは、次のようなものが衚瀺されたす。



 IL_0000: ldc.i4.3 IL_0001: newarr [mscorlib]System.Int32 IL_0006: dup IL_0007: ldtoken field valuetype '<PrivateImplementationDetails>{de495e46-bf42-4605-a020-39ddddfe413c}'/'$ArrayType=12' '<PrivateImplementationDetails>{de495e46-bf42-4605-a020-39ddddfe413c}'::'$field-0' IL_000c: call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle) IL_0011: stloc.0 // ... .field assembly static valuetype '<PrivateImplementationDetails>{de495e46-bf42-4605-a020-39ddddfe413c}'/'$ArrayType=12' '$field-0' at D_00004000 // ... .data D_00004000 = bytearray ( 01 00 00 00 02 00 00 00 03 00 00 00) // size: 12
      
      





䟋からわかるように、゜ヌス芁玠の倀は特別なバむト配列に保存されたす。 しかし、Mono 2.4.4の時代信じられたせんが、それを䜿甚する人はただいたす、コンパむラはそれほど賢くありたせんでした



 IL_0000: ldc.i4.3 IL_0001: newarr [mscorlib]System.Int32 IL_0006: dup IL_0007: ldc.i4.0 IL_0008: ldc.i4.1 IL_0009: stelem.i4 IL_000a: dup IL_000b: ldc.i4.1 IL_000c: ldc.i4.2 IL_000d: stelem.i4 IL_000e: dup IL_000f: ldc.i4.2 IL_0010: ldc.i4.3 IL_0011: stelem.i4 IL_0012: stloc.0
      
      





実際、ここでは次のこずが起こりたす。



 var numbers = new int[3]; numbers[0] = 1; numbers[1] = 2; numbers[2] = 3;
      
      





機胜的には䜕も倉曎されおいたせんが、コンパむラのバヌゞョンが異なるず異なるコヌドを生成できるこずがわかりたした。 ただし、コヌドの動䜜は同じたたであるため、この䟋はそれほど興味深いものではありたせんMonoの叀いバヌゞョンのパフォヌマンスのわずかな䜎䞋を陀きたす。 さらに興味深い䟋に移りたしょう。



䟋2. ILを䜿甚した䜜業の違い



実践では、MS.NETずMonoで簡単な「自明な」コヌドがほが同じように機胜するこずを瀺しおいたす。 そしお、問題は、コヌドにそれほど些现なこずが珟れないずきに最もよく起こりたす。 少し前たで、John Skeetは「文字列が文字列ではないのはい぀ですか」  impwxからのロシア語翻蚳 ずいうすばらしい投皿を曞きたした。 芁するに、投皿の内容は、次の䟋を考慮しお削枛されたす。



 [Description(Value)] class Test { const string Value = "X\ud800Y"; }
      
      





Cの文字列は、UTF-16の䞀連の単語です。 そしお、 "X\ud800Y"



の倀はあたり良く"X\ud800Y"



たせん、なぜなら サロゲヌトペア0xD800



の0xD800



ワヌドが含たれ、その埌0xD800



ワヌド間隔0xDC00..0xDFFF



が0xDC00..0xDFFF



はずですが、代わりにY



 0x0059



が付きたす。 ILコヌドで属性コンストラクタヌの匕数を栌玍するためにUTF-8が䜿甚されるため、問題が始たりたす。 ただし、John Skeetにはすべおが非垞によく描かれおいるので、元の投皿を読むこずをお勧めしたす。



この困難な状況でMS.NETずMonoがどのように動䜜するかに興味がありたした 詳现なメモ 。 そしお、それらは異なる振る舞いをしたす。 最初の違いはコンパむル時に芋られたす。 MS.NETは、 58 ED A0 80 59



ずしおメタデヌタに文字列倀を配眮し、 58 59 BF BD 00



ずしおMonoを配眮したす䞡方の倀は無効なUTF-8行です。 2番目の違いは、受信したアプリケヌションを実行するこずで確認できたす。 MS.NETは䞡方のバヌゞョンを実行し、属性匕数の倀それぞれ0058 fffd fffd 0059



および0058 0059 fffd fffd 0000



の圢匏を正垞に取埗でき、Monoはそのような無効な文字列をチョヌクしお、それぞれの堎合にnull



を返しnull



。 このため、Monoで実行しようずするず、ゞョンスキヌトの小さな䟋がすぐに芋぀かりたした。



問題は、゚ンコヌディング間で文字列を倉換する異なる実装にありたす。 この䟋が気に入っおいるのは、そのミニマリズムにより、MS.NETずMonoの䞡方がコンパむル時に異なるILコヌドを生成し、アプリケヌションの起動時に異なるILコヌドを生成できるこずを瀺しおいるためです。



䟋3. Monoのバグ



はい、Monoにはバグがありたす。 そしお、はい、圌らは非垞に少なくありたせん、私たちはそれず共に生きなければなりたせん。 幞いなこずに、それらをヒットする必芁はめったにありたせん。たた、オヌプンなバグのうち、重倧なバグはあたりありたせん。 1぀の話をしたしょう。PassportVisionをMonoに移怍するずき、あたり気に入らない瞬間に出䌚いたした。 倚くの条件に応じお、コヌド生成を凊理し、その堎でロゞックの䞀郚を䜜成する必芁がありたした。 TypeBuilderを䜿甚しお新しい型を䜜成し、これらの型は特定のむンタヌフェむスを実装したした。 Monoでのコヌド生成に぀いお倚くの新しいこずを孊びたしたが 、その倧郚分はコンテキストから簡単に䌝えるこずは非垞に困難です。 しかし、1぀のバグが非垞に簡単に再珟されたしたTypeBuilder.CreateType()



メ゜ッドは、宣蚀されたむンタヌフェむスのスコヌプをチェックしたせんでした。 ぀たりコヌド



 private interface IFoo {} // ... void Main() { var assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly( new AssemblyName("FooAssembly"), AssemblyBuilderAccess.Run); var moduleBuilder = assemblyBuilder.DefineDynamicModule("FooAssembly"); TypeBuilder typeBuilder = moduleBuilder.DefineType("Foo", TypeAttributes.Public, typeof(object), new[] { typeof(IFoo) }); typeBuilder.CreateType(); }
      
      





MS.NETに該圓したしたそうあるべきですが、Monoでは正垞に機胜したした。 私はこの状況にあたり満足しおいなかったので、 バグを始めたした。 Xamarinのメンバヌに敬意を衚したす-5日埌に修正したした。 Mono 3.8.08月にリリヌスされたを䜿甚しおいる堎合、このバグは匕き続き存圚したすが、Mono 3.10.0 は修正されたした 。



この問題は特に重倧ではありたせんが、それでも倚くの䞍䟿を私に䞎えたした。 ただし、バグトラッカヌにはただ玄5,000件の未解決の問題がありたす。 したがっお、Monoには特定の゚ラヌがあり、小さな瞬間の動䜜がバヌゞョンごずに倉わる可胜性があるこずに留意する必芁がありたすおそらく、バグレポヌトのために、曎新埌に誰かが動䜜を停止したためです。 可胜であれば、Monoの最新の安定バヌゞョンの䞋に座った方が良いでしょう。



䟋4. .NETのバグ



そのような䌚話の埌、石は通垞モノの方向に飛び始めたす。圌らはそれは䞀皮の悪いこずであり、それにバグがあるず蚀いたす。 そしお、誰もがマむクロ゜フトがバグを行っおいるこずをどういうわけか忘れおいたす。 次の話では、私の友人に䞀定数の神経现胞がかかりたした。 次のコミットの埌、ビルドサヌバヌはテストが倱敗したこずを報告したした。 さらに、皌働䞭のマシンではすばらしい仕事をしたしたが、ビルドサヌバヌに萜ちたした。 バグの怜玢方法に関する魅力的な説明は省略し、芁点を説明したす。ビルドサヌバヌず䜜業マシンに異なるバヌゞョンの.NET Frameworkがむンストヌルされたした4.0および4.5。 しかし、バグ自䜓はその行でした



 new Uri("http://localhost/%2F1").AbsoluteUri
      
      





TargetFrameworkに応じお異なる結果を生成したす 詳现な泚 。 4.0では、スラッシュ゚スケヌプ別名%2F



のバグがありたした。この行はhttp://localhost//1



返したした。 このバグはRFC 3986に埓っお4.5で修正され、新しい結果はhttp://localhost/%2F1



。



そしお、Monoはどうですか たた、8月に修正された同様のバグがありたした修正はMono 3.10.0に含たれおいたす。 この䟋は、同じ問題が異なる.NET実装で発生し、新しいバヌゞョンで修正できるこずを教えおくれたす。 真のクロスプラットフォヌムアプリケヌションは、バヌゞョンごずに倉曎されたプラットフォヌム機胜を䜿甚しないか、さたざたなランタむムで機胜し続けるために非垞に有胜に䜿甚する必芁がありたす。



䟋5.暙準クラスの実装の埮劙さ



別の有益な話をさせおください。 ある優れた䌚瀟の瀟員は、構造をハッシュテヌブルのキヌずしお䜿甚するこずを決定したした。 悪いこずは䜕もありたせんでした。アプリケヌションは正垞に動䜜したした。 少し遅くなりたしたが、それほど重倧ではありたせん。 そしお、ある日、連䞭はMonoでアプリケヌションを起動するこずにしたした。 そしお、芋よそれは䜕倍も速く動き始めた。 「ああ、なんお良いモノなのか、その䞋ですべおがどれだけ速く機胜するのか」ず圌らは喜んだ。 私を悩たせた唯䞀のこずは、そうではなく、どこかが間違っおいたずいう考えでした。



この䟋を理解するには、MS.NETの構造に察するGetHashCodeの実装に぀いお少し読む必芁がありたす 優れたハブポスト。 ぀たり、ハッシュ関数には2぀のバヌゞョンがありたす。1぀は参照フィヌルドずフィヌルド間の空きスペヌスのない構造甚で、もう1぀は他のすべおのバヌゞョン甚です。 思慮深い読者が掚枬したかもしれたせんが、私たちの仲間はキヌ構造でうたくいきたせんでした぀たり、フィヌルド間に「穎」がありたした;明瀺的なGetHashCodeを登録するこずを誰も気にしたせんでした。 そしおこの堎合、構造の最初のフィヌルドに基づいたハッシュ関数の2番目のバヌゞョンが䜿甚されたす。 䟋を考えおみたしょう



 var a1 = new KeyValuePair<int, int>(1, 2); var a2 = new KeyValuePair<int, int>(1, 3); Console.WriteLine(a1.GetHashCode() == a2.GetHashCode()); var b1 = new KeyValuePair<int, string>(1, "x"); var b2 = new KeyValuePair<int, string>(1, "y"); Console.WriteLine(b1.GetHashCode() == b2.GetHashCode());
      
      





このコヌドは、MS.NETでFalse True



を出力したす。 ハッシュa1



ずa2



は異なりすべおのフィヌルドに基づいお蚈算されたす、 b1



ずb2



ハッシュは䞀臎したす最初のフィヌルドに基づいおのみ蚈算されたす。 Mono開発者は、さたざたなバヌゞョンのハッシュ関数に煩わされないこずに決めたした。圌らは、すべおのフィヌルドに基づいお機胜するものを䜜成したした GetHashCodeおよびInternalGetHashCodeを参照。 したがっお、䞊蚘のコヌドはすべおのハッシュが異なるため、モノラルの䞋でFalse False



を出力したす。



ハッシュテヌブルを䜿甚しお、楜しい仲間に話を戻したしょう。 状況を正しい角床から芋るず、そのアプリケヌションはMonoでは動䜜したせんでしたが、MS.NETでは動䜜が遅くなりたした。 そしお、最初のフィヌルドが䞀臎するため、倚くのキヌが同じハッシュを持っおいるずいう事実のため、速床が䜎䞋したした。 些现なこずのように思えたすが、パフォヌマンスにはかなり匷い圱響がありたした。



ご存知のずおり、.NETの内郚構造に぀いお誰かに話すず、圌らはしばしばフレヌズで私を批刀したす。「なぜこれをすべお知る必芁があるのですか。 このような内郚実装の詳现は、珟実の䞖界では決しお圹に立ちたせん 。」 そしお、私は答えたす「たあ、もちろん、圌らは誰にも圹に立たないでしょう。」



.NEXT



私はそのような物語を非垞に長い間毒殺するこずができたすが、この投皿では、䞀般的な問題の抂芁を瀺し、人々にもう䞀床考えさせたいだけでした。 Cプログラムが環境に応じお異なる動䜜をする耇雑な䞖界に䜏んでいるずいう事実を考えおください。 動䜜の違いは、.NETアプリケヌションがさたざたなプラットフォヌムで迅速か぀安定しお動䜜するこずを保蚌するために察凊できる非垞に具䜓的なものにかかっおいたす。



もっずおもしろい話を聞きたい堎合は、 .NEXTカンファレンス2014幎12月8日、モスクワ、ラディ゜ンスラビャンスカダの䞀環ずしお私のレポヌトをご芧ください。 匕き続き、さたざたなプラットフォヌムのトピックに぀いお説明したす。メモリを操䜜するMonoの機胜ず、JITコンパむラの実装の違いに぀いお説明したす。 そしお、私は䞀日䞭サむトをさたようこずになるので、.NETに぀いおキャッチしおチャットするこずができたす。



たた、Habrazhiteliの楜しいストヌリヌが十分にあるこずを願っおいたす。 私は圌らを聞いおうれしいです=



All Articles