Movatterモバイル変換


[0]ホーム

URL:


信之 岩永, profile picture
Uploaded by信之 岩永
PPTX, PDF60,354 views

C#や.NET Frameworkがやっていること

2014/3/1 Boost勉強会 #14 東京 にてhttps://sites.google.com/site/boostjp/study_meeting/study14Boost勉強会なのに.NETの話で、1人だけ1時間(他の人は30分)。本来、自分のペースでは4時間くらいかかってもおかしくない分量を1時間で。

Embed presentation

Downloaded 319 times
C#や.NET Frameworkがやっていること岩永 信之
自己紹介C#でぐぐれこんなロゴのサイトの中の人プログラミングの魔導書 Vol.3にも何か書いてるよ
今日の内容• C#や.NET Frameworkがやっていること• どうしてそういう機能がある• (自前で実装するなら)どうやればできる• (自前でやる上で) 気を付ける必要がある点
趣旨• 言語的に機能がないからって、やらなくていいわけじゃない。• C#とかが持ってる機能は必要だから追加されてる• 自前で同様のことをやる方法も知ってて損ない• 例えば…• C言語でもOOPやってる人はやってた• C言語でも仮想関数テーブル自前で書いたり
注意170ページ• 本来、1時間で話す内容じゃない• 置いてきぼる気満々• あんまり細かい説明しない(というかできない)
まずは.NET Frameworkといえば“Managed”
“Managed”• .NET Frameworkの管理下にある• メモリ管理• メモリ解放• 境界チェック• ドメイン分離• 型の管理• メタデータ• JIT• PCL
Garbage Collectionメモリ リークをなくすために
.NET FrameworkのGC• .NET FrameworkのGCはMark & Sweep• 世代別 (3世代、Gen0~2)• Compactionあり• Backgroundスレッドで並列実行
Mark & Sweep• ルート†から参照をたどるルートヒープMark使用中オブジェクトSweep未使用オブジェクト†スタックや静的フィールド中のオブジェクト
Compaction• GC時にオブジェクトの位置を移動隙間をなくすように移動後ろが丸ごと空くので次のメモリ確保が楽使用中オブジェクト未使用オブジェクト
Generation• GC時にオブジェクトの位置を移動オブジェクトの寿命統計的に• 短いものはとことん短く• 長いものはとことん長いGen0Gen1しばらくここはノータッチGen0この範囲でだけメモリ確保・GC一度GCかかったオブジェクトはしばらく放置
C++でのGC• 通常、参照カウント• shared_ptr• 循環参照に気を付けて適宜weak_ptrを• Mark & Sweep GCライブラリもあるけども• 型がはっきりしないので保守的にならざるを得ない• すべての数値をポインターとみなしてMark
Mark & Sweepと参照カウント• 比較• 一長一短あるMark & Sweep参照カウントメモリ確保○ 末尾を見るだけ× 空いている場所を探す× カウント用の領域が追加で必要変数のコピー○ ポインターのコピー× ポインターのコピーに加え、参照数のカウントアップメモリ解放× MarkやCompactionに時間がかかる× 負担が1か所に集中○ カウントが0になった時にdeleteするだけ
Throughput• トータルの性能(throughput)はMark & Sweepの方がいいMark & Sweepメモリ確保参照カウント○ 末尾を見るだけ× 空いている場所を探す× カウント用の領域が追加で必要○ ポインターのコピー変数のコピー 参照局所性も高くなってキャッシュが効きやすいメモリ解放× MarkやCompactionに時間がかかる× 負担が1か所に集中まとめてやる方がバラバラにやるより効率がいい× ポインターのコピーに加え、参照数のカウントアップ頻度が高い操作なので○ カウントが0になった時ここの負担が大きいとにdeleteするだけ全体の性能落ちる特に、スレッド安全を求めるときついたかがインクリメントでも、atomic性保証するとそこそこの負担
短所の軽減• 短所も、まったく打つ手がないわけじゃないMark & Sweep参照カウントメモリ確保○ 末尾を見るだけ× 空いている場所を探す× カウント用の領域が追加で必要変数のコピー○ ポインターのコピー× ポインターのコピーに加え、参照数のカウントアップメモリ解放.NET 4以降、Backgroundスレッド実行してる× MarkやCompactionに時間がかかる× 負担が1か所に集中○ カウントが0になった時C++ 11的にはにdeleteするだけ「move semantics活用してね」
自前メモリ管理との混在• スコープが短いならスタックにとればいいのに• C#はclassは必ずヒープ、structはスタックになる• 使い分けれない• Mark & Sweep管理領域内のポインターを管理外に渡すときには注意が必要• Compactionでメモリ移動しないように「ピン止め」が必要• 結構ガベージ コレクションのパフォーマンス落とす
おまけ• Pythonとか• 参照カウントとMark & Sweepの併用• ○ 循環参照問題避けつつ、負担を1か所に集中させない• × 性能的には悪いとこどり• Go• 割当先を自動判別• スコープ内で完結していたらスタックに• そうでなければヒープに• これはこれでスタックの浪費激しそうなんだけども…• なので、可変長スタック持ってる
境界チェック意図しないメモリ領域にはアクセスさせない
配列の境界チェック• .NETの配列は厳しい• 常に境界チェックしてる配列 aa[-1]OutOfRangea[length+1]OutOfRange• 要はbuffer overrun防止• ちなみにJITの最適化で、明らかに境界を侵さないものは境界チェックを消す
unsafe• C#にもポインターあるんだけども安全でないコードこの中でだけポインター利用可能var x = new[] { 1, 2, 3, 4, 5 };unsafe{fixed(int* px = &x[0])メモリ移動の防止{(ピン止め)Console.WriteLine(px[100]);}}範囲チェックなしbuffer overrunやりたい放題
unsafeでも制限付き• class (参照型)はアドレス取れない• 仮想メソッド テーブル(vtable)とか入ってるし• 親クラス側のレイアウト変更の影響受けるしclass Classvar c{fixedpublic int x;fixedpublic int y;fixed}ピン止め必須••= new Class();(void* p = &c) { }// error(void* p = &c.x) { } // OK(void* p = &c.y) { } // OK値型のメンバーのアドレスは取れるオブジェクト自体のアドレスは取れない
unsafeでも制限付き• struct (値型)はアドレス取れる• ただし、メンバーが全部値型の時のみ• ↑「unmanaged型」と呼ぶstruct UnmanagedStruct{public int x;public int y;}メンバーが全部値型var uvoid*void*void*= new UnmanagedStruct();p1 = &u;// OKp2 = &u.x; // OKp3 = &u.y; // OK無制限にアドレス取れる
unsafeでも制限付き• struct (値型)であっても制限付き• メンバーに1つでも参照型を含むとダメ• ↑「managed型」と呼ぶstruct ManagedStruct{public int x;public string y;}メンバーに参照型が1つvar uvoid*void*void*= new ManagedStruct();p1 = &u;// errorp2 = &u.x; // OKp3 = &u.y; // error値型のメンバーのところだけはアドレス取れる
ポイント• unsafe• 危険なことは基本認めない• 面倒な追加の構文を要求• コンパイル オプションでも/unsafeの明記必須• fixed• ガベージ コレクションとの兼ね合い• Compaction阻害になるので注意• 「Unmanaged型」に限る• 実装依存な部分(vtableとか)や、型の定義側の変更が利用側に極力影響しないように
AppDomain実行環境の分離セキュリティ保証
コンポーネントの連携• 他のアプリの機能を自分のアプリから呼びたい• WordとかExcelとかのドキュメントを出力• サーバー上に自分のアプリを配置したい• IIS上に(ASP.NET)• SQL Server上に• (必ずしも)信用できない• セキュリティ保証• 参照先のクラッシュにアプリ/サーバーが巻き込まれないように• コンポーネントのバージョン アップ
AppDomain• 単一プロセス内で、分離された複数の実行領域(domain)を提供プロセスAppDomain 1AppDomain 2…必ずしも信用できないコードを安全に、動的に呼び出し• 「分離」• plugin: 動的なロード/アンロード• security: AppDomainごとに異なる権限付与• isolation: 別メモリ空間
ドメイン間には壁がある• 別メモリ空間に分離されてるAppDomain 1AppDomain 2互いに独立
ドメイン間の通信• マーシャリング(marshaling)• marshal (司令官、案内係)の命令通りにしか壁を超えれない• 司令がダメといったら通れない• 司令の指示通りの形式にいったんシリアライズしないといけないAppDomain 1AppDomain 2
ドメイン間の通信• ダメな例あるオブジェクトAppDomain 1これをBに渡したいとしてAppDomain 2
ドメイン間の通信• ダメな例AppDomain 1AppDomain 2shallow copyなんてしようもんならA側のメモリへの参照が残る
ドメイン間の通信• よい例一度シリアライズ必ずdeep copy{{1, 2},{3, 4},{5, 6}serializeAppDomain 1}deserializeAppDomain 2この辺りがマーシャリング
.NETのマーシャリング• 2種類• marshal by ref• 参照を渡すんだけど、メモリ領域は直接触れない• メソッド越しにしか操作しちゃいけない• 「このメソッドを呼んでくれ」っていうメッセージだけがドメインを超えてわたって、実際の実行は相手側ドメインで• marshal by value• 値をシリアライズして相手側に渡す• 規定では、BinarySeralizerを使用privateフィールドまで含めてリフレクションで内部状態を取得してシリアライズ
.NETのマーシャリング(文字列)• marshal by valueの場合でも文字列は特殊扱い• コピーしない• 参照をそのまま渡す• immutableかつrange-check付きに作ってある• COM (ネイティブ)に対して文字列を渡す時すらこの方式(ただし、文字コード変換が不要な場合だけ)
その他のコスト(マーシャリングのコスト以外にも)• いくらかコストが• 例えばライブラリの読み込みLibrary XAppDomain 1Library XAppDomain 2別ドメインに全く同じライブラリを読み込んでも、それぞれ別イメージが作られるGlobal Assembly Cache (GAC)にあるDLLだけは別GAC中のは同じメモリ イメージが共有される
C++でも• COMなんかはマーシャリングやってる• 逆にいうと、COMくらい仰々しいものが必要• さもなくば、プロセス分離してプロセス間通信とかやらなきゃいけない• 安全だけどかなり高負荷• RPCとか一時期流行ったけども• ただの関数呼び出しに見えるコードで、内部的にプロセス間通信するとか
メタデータ型情報動的リンクでのバージョン管理
メタデータ• メタデータとは• DLLにどういう型が含まれるかという情報• 外部のどういうDLLを参照しているかの情報• バージョン情報• メタデータがあると• プログラミング言語をまたげる• 動的リンクでのバージョン管理
動的リンク• ライブラリは共有するアプリAライブラリXversion 1アプリBライブラリYversion 1
動的リンク• ライブラリ単体での差し替え• セキュリティ ホールや、致命的なバグの修正差し替えアプリA更新不要ライブラリXversion 2アプリBライブラリYversion 1
いまどきの事情• ライブラリはアプリのパッケージに同梱• バージョニングいるの?アプリAパッケージアプリAアプリBパッケージライブラリXライブラリYライブラリXアプリB別バイナリライブラリY
差分ダウンロード※ Windowsストア アプリはこの仕組み持ってるらしいアプリAパッケージ version 1アプリAversion 1アプリAパッケージ version 2ライブラリXversion 1アプリAversion 1ライブラリYversion 1ライブラリXversion 2ライブラリYversion 1差分ライブラリXversion 2バージョンアップ時ダウンロードアプリA ver.1インストール機
アプリ間でライブラリ共有※ Windowsストア アプリはこの仕組み持ってるらしいアプリAパッケージアプリAアプリBパッケージライブラリXversion 1ライブラリXversion 1アプリBライブラリYversion 1ライブラリYversion 1差分アプリBアプリBインストール時X、Yは同じものを共有(ハード リンク作るだけ)アプリAインストール機
メタデータの作成• COMの頃• メタデータを自分で書いてた(自動化するツール使あるけど)• .tlb/.olbファイル• .NET Framework• .NET自体ががメタデータの規格を持ってる• C#とかをコンパイルするだけで作られる
C++/CX• C++ Component Extensions• マイクロソフトのC++拡張素の標準C++コードC++/CXコンパイルC++内で完結して使う分にはオーバーヘッドなしCOMコードCOMを呼べる言語なら何からでも呼べるメタデータ(winmd).NETのメタデータと互換.NETから簡単に呼べる
JIT(Just-in-Time compile)バージョン アップ時の変更の影響を吸収
中間コードとJITコンパイル• .NET Frameworkの中間言語ビルド時にコンパイル高級言語(C#など)Just-in-Timeコンパイル中間言語ネイティブ(IL)コードJITである必要ないLLVMとかでも中間言語介してコンパイルしてる• 高級言語のコンパイラーを作る人と、CPUごとの最適化する人の分業化 ストア審査ではじくとか他にも手段はある• セキュリティ チェックしやすくなったり• 動的リンク時に、コード修正の影響をJITで吸収
例• (C#で)こんな型があったとしてpublic struct Point{public int X;public int Y;public int Z;}• 整数のフィールドを3つ持つ
例• こんなメソッドを書いたとするstatic int GetVolume(Point p){return p.X * p.Y * p.Z;}• フィールドの掛け算
IL• C#コンパイル結果のIL.method private hidebysig static int32GetVolue(valuetype Point p) cil managed{.maxstack 8型とかフィールドIL_0000: ldarg.0IL_0001: ldfldint32 Point::Xの名前がそのままIL_0006: ldarg.0残ってるIL_0007: ldfldint32 Point::YIL_000c: mul型情報IL_000d: ldarg.0メタデータIL_000e: ldfldint32 Point::ZIL_0013: mulIL_0014: ret}
ネイティブ コード• JIT結果 (x64の場合)pushmovcmpjecallmovleaimulleaimulpopretebpebp,espdword ptr ds:[5011058h],000FE2A0174B7AEA8eax,dword ptr [ebp+8]edx,[ebp+8]eax,dword ptr [edx+4]edx,[ebp+8]eax,dword ptr [edx+8]ebp0Ch4とか8とかの数値に型情報は残らない
メモリ レイアウト• この4とか8の意味PointXpublic struct Point{public int X;public int Y;public int Z;}Y4バイト8バイトZ※レイアウトがどうなるかは環境依存
メモリ レイアウト• この4とか8の意味ILの時点までは名前で参照してるpublic struct PointPointX{public int X;public int Y;public int Z;}Y4バイト8バイトネイティブ コードはレイアウトを見てZ数値で参照してる※レイアウトがどうなるかは環境依存
数値でのフィールド参照• C#で擬似的に書くとstatic int GetVolume(Point p){return p.X * p.Y * p.Z;}var pp = (byte*)&p;var x = *((int*)pp);var y = *((int*)(pp + 4));var z = *((int*)(pp + 8));return x * y * z;4とか8とかの数値に※これ、一応C#として有効なコード(unsafe)
変更してみる• 大して影響しなさそうなほんの些細な変更をしてみるpublic struct Point{public int X;public int Y;public int Z;}public struct Point{public int X;public int Z;public int Y;}フィールドの順序変更
その結果起きること• メモリ レイアウトが変わる※PointPointXXYZZY※ この例(フィールド変更)以外でも、仮想メソッドとかいろいろレイアウトが変わるものがあるテーブル
ILレベルでの影響• 影響なしIL_0000:IL_0001:IL_0006:IL_0007:IL_000c:IL_000d:IL_000e:IL_0013:IL_0014:ldarg.0ldfldldarg.0ldfldmulldarg.0ldfldmulretint32 Point::Xint32 Point::Yint32名前で参照してるんだから特に影響ないPoint::ZJITが吸収してくれる
ネイティブ レベルでの影響• ここで影響が出るpushmovcmpjecallmovleaimulleaimulpopretebpebp,espdword ptr ds:[5011058h],000FE2A0174B7AEA8eax,dword ptr [ebp+8]edx,[ebp+8]eax,dword ptr [edx+4]8edx,[ebp+8]更新が必要4eax,dword ptr [edx+8]ebp0Ch利用側の再コンパイルが必要ライブラリ側だけの差し替えじゃダメ
ただし…• この役割に焦点を当てるなら…• 毎回毎回JITする必要ない• 全部が全部ILな必要ない
Ngen• Ngen.exe• Native Image Generator• ILを事前にネイティブ化するためのツール• 自前管理が必要• アプリのインストーラー※とかを作って明示的に呼び出し• 参照しているライブラリが更新された時には呼びなおす必要あり• かなり面倒なのでアプリをNgenすることはめったにない• .NET自体が標準ライブラリの高速化のために使ってる※要するに、JITの負担を起動時じゃなくてインストール時に前倒しする
Auto-Ngen• .NET Framework 4.5以降なら• NgenがWindowsサービスとして常に動いてる• アイドル時に動作• 利用頻度の高いものを自動的にNgen• デスクトップ アプリの場合はGACアセンブリのみ• Windowsストア アプリの場合はすべてのアセンブリ• よく使うアプリの起動はだいぶ早くなる• インストール直後の起動は相変わらず遅い
MDIL (ネイティブのおさらい)• おさらい: ネイティブ コードだとpushmovcmpjecallmovleaimulleaimulpopretebpebp,espdword ptr ds:[5011058h],000FE2A01参照しているライブラリ74B7AEA8eax,dword ptr [ebp+8] のレイアウトが変わったedx,[ebp+8]時に再コンパイルが必要eax,dword ptr [edx+4]edx,[ebp+8]eax,dword ptr [edx+8]ebp0Ch
MDIL (部分的にネイティブ化)• じゃあ、こんな形式があればいいんじゃ?pushmovcmpjecallmovleaimulleaimulpopretほぼネイティブebpレイアウトのところebp,espdword ptr ds:[5011058h],0 だけ抽象的に型情報00FE2A01を残しておく74B7AEA8eax,dword ptr [ebp+8]Point::Xint32edx,[ebp+8]eax,dword ptr [edx+4]Point::Yint32edx,[ebp+8]eax,dword ptr [edx+8]Point::Zint32ebp0Ch
MDIL (Compile in the Cloud)• 実際、Windows Phoneのストアではそういう形式が使われている: MDIL(Machine Dependent Intermediate Language)C#コードC#コンパイラー開発環境でILにコンパイルMDILコンパイラーWindowsストア サーバー上でILをMDIL化(Compile in the Cloud)ILMDILリンカーネイティブ コードWindows Phone実機上ではレイアウトの解決(リンク)だけ行う• インストール直後の起動も安心
C++だと• 動的にやろうと思ったら、結局、COMとかWinRTになってく• いったんQueryInterfaceみたいなの挟む• 結構でっかいオーバーヘッド†† WinRTはオーバーヘッド解消の仕組みも持ってて、C++で完結してる限りには普通の仮想関数呼び出しになる他言語から使う場合にはCOMアクセスになる
C++だと• 静的な話で言うとヘッダーファイルを変更したら利用側の再コンパイルが必要Point.hstruct Point{double x;double y;};struct Point 要 再コンパイル{double radius;double theta;};
なので• setter/getter使う• pimpl使うPoint.cpp (実装その1)struct PointImpl;struct PointImpl{double x;double y;};class Point{public:double get_x();double get_y();private:PointImpl* impl;};double Point::get_x(){return impl->x;}double Point::get_y(){return impl->y;}Point.h
なのでPoint.cpp (実装その2)こっちだけの変更なら、setter/getter使う利用側の再コンパイル不要•• pimpl使うPoint.h変更なしstruct PointImpl;class Point{public:double get_x();double get_y();private:PointImpl* impl;};struct PointImpl{double radius;double theta;};double Point::get_x(){return impl->radius* cos(impl->theta);}double Point::get_y(){return impl->radius* sin(impl->theta);}
Portable Class Library複数の「標準ライブラリ」いろんな実行環境の共通部分
標準ライブラリ• マイクロソフト製品だけでも…デスクトップクライアント アプリこの共通部分だけを「標準」にすべき?共通部分サーバー アプリPhone/タブレットクライアント アプリ
標準ライブラリ• まして今、Xamarin (Mono)• Xamarin.iOS、Xamarin.AndroidWindowsタブレット/PhoneWindowsデスクトップWindowsサーバーiOSAndroidこの共通部分だけを「標準」にすべき?Linuxサーバー
.NET FrameworkとMonoコンパイラー.NETFramework実行環境C#VBCLRF#ライブラリ.NET Fullプロファイル.NET Coreプロファイル.NET Full(サブセット)MonoC#MonoランタイムiOS向けプロファイルAndroid向けプロファイル実行環境に互換性があっても標準で使えるライブラリが違う
どこでも使えそうに見えても…• 例えばファイル システム• 最近のWindowsはいろんなプロパティを持ってる• 画像ファイルなんかだと:サムネイル画像、撮影日時、画像サイズ、タグ• 検索インデックスも張ってるこういうものも標準に含めたいか?• ストア アプリだとファイル システムすら制限下• ユーザーの許可がないファイルには触れない一番制限がきつい環境に合わせて標準ライブラリを作るべき?
汎用 VS 特定環境どこでも動く特定環境で動く• 最大公約数• 動作保証に時間がかかる• 高機能• 早く提供できる
汎用 VS 特定環境どこでも動く• 最大公約数• 動作保証に時間がかかるC++だと• 標準化にかかってる時間特定環境で動く• ライブラリのソースコードをとってきたは• 高機能いいけど自分の環境での動作確認も大変• 早く提供できる
Portable Class Library• 実行環境ごとに別の「標準ライブラリ」メタデータを用意• ライブラリ側でどの実行環境をターゲットにするか選ぶ実行環境ごとに別メタデータを提供ターゲット選択
Portable Class Library• 例: 2環境共通部分
Portable Class Library• 例: 3環境共通部分
C++• ターゲット広すぎてより一層大変だけど• メタデータ持ってない言語でやるのも厳しい• #ifdef?
さてもうすでに約80ページ
ここまで/ここから• ここまで: .NETのインフラ的なところ• いわゆる“Managed”• C# 1.0の頃からある基本機能• 所詮、既存言語をManagedにした程度• ここから: C# 2.0以降の追加機能
C#の歴史C# 4.0C# 3.0C# 2.0C# 1.0• DynamicC# 5.0• Async• WinRT• LINQ• Generics• Managed※VB 7~11の歴史でもある
ジェネリックC# 2.0C++で言うところのtemplateC++ templateと.NET Genericsの違い
C++ templateとC# genericsC++ templateC# generics高機能マクロみたいなもので、コンパイル時に全部展開される.NETの中間言語/型情報レベルで対応JIT時に展開vector<T>とvector<U>で別コードが生成されるList<T>とList<U>で同じコードを共有(参照型の場合)すべてヘッダーに書く必要がある変更すると利用側も再コンパイル内部を変更しても(publicなところが変わらない限り)利用側に影響なしコンパイル時にすべてやる方針メタデータ/JITで話した要件• 言語をまたげる• 動的リンク• バージョン管理• 利用側に影響与えない.NET的にはこれを守るのが最重要
もしC++でgenericsやるなら(動的には無理だけど、せめて静的に)• いったん汎用クラスを作るclass void_vector{public:void* operator[](int index);void add(void* item);void remove(void* item);… 後略 …いったんvoid*な汎用クラスを作る
もしC++でgenericsやるなら(動的には無理だけど、せめて静的に)• キャストだけtemplateでtemplate<typename T>class vector<T>{さっき作ったvoid*のクラスprivate:void_vector impl; キャストするだけの薄いtemplateクラスを作る要素の型が保証されるのでstatic_castでOKpublic:T* operator[](int index){return static_cast<T*>(impl[index]);}void add(T* item) { impl.add(item); }void remove(T* item) { impl.remove(item); }};
もしC++でgenericsやるなら• このやり方(汎用クラス+templateでキャスト)なら• vector<T>とvector<U>でコード共有可能• バイナリ サイズ小さくできる• (pimplを併用すれば)内部実装を変更しても、利用側の再コンパイル不要• コンパイル時間だいぶ短くできる
とはいえ、いろいろ窮屈• genericsでは、インターフェイス制約かけないとメソッドすら呼べないstatic Type Max<Type>(Type a, Type b){return a.CompareTo(b) > 0 ? a : b;}コンパイル エラーそんなメソッド知らない正しくはstatic Type Max<Type>(Type a, Type b)where Type : IComparableインターフェイス制約{return a.CompareTo(b) > 0 ? a : b;}IComparable.CompareTo
とはいえ、いろいろ窮屈• 特に困るのが演算子使えないこと• 実体は静的メソッドなのでstatic T Sum<T>(T[] array){T sum = default(T);foreach (var x in array) sum += x;return sum;}コンパイル エラー演算子定義されてない
とはいえ、いろいろ窮屈• dynamicでごまかせなくはないけども…• 性能出ないので最後の手段static T Sum<T>(T[] array){dynamic sum = default(T);foreach (var x in array) sum += x;return sum;}実行時コード生成で+演算子が呼ばれる
C++/CX• C++/CXはジェネリックを持ってる• genericキーワード• メタデータ(winmd)上は.NETのジェネリックと互換• かなり制限きつい• 実装(genericなクラス)はpublicにできない• private/internalなクラスはtemplateで展開• ユーザー定義のインターフェイス、デリゲートもgenericな場合はpublicにできない
イテレーターC# 2.0イテレーター生成用の構文
イテレーター ブロック• C++的な意味のイテレーターの生成を楽にするstd::vector<int> v{ 1, 2, 3, 4 };for (auto p = v.begin(); p != v.end(); ++p)std::cout << *p << std::endl;こういうの• 使う側(forループ側)は楽でいいんだけども• 実装側(vector_iteratorの中身)はめんどくさいこれを楽にする
例• substringの列挙実装側static IEnumerable<string> GetSubstrings(string s){for (var len = s.Length; len >= 1; len--)for (var i = 0; i <= s.Length - len; i++)yield return s.Substring(i, len);}イテレーター ブロック†(= yield returnを持つ関数ブロック)使う側foreach (var x in GetSubstrings("abcd"))Console.WriteLine(x);
内部実装(全体像)• クラス生成class SubstringEnumerable : IEnumerator<string>, IEnumerable<string>{readonly string _s;int _len;int _i;int _state = 0;public SubstringEnumerable(string s) { _s = s; }public string Current { get; private set; }public bool MoveNext(){if (_state == 1) goto STATE1;if (_state == -1) goto END;_state = 1;_len = _s.Length;LOOP1BEGIN: ;if (!(_len >= 1)) goto LOOP1END;_i = 0;LOOP2BEGIN: ;if (!(_i <= _s.Length - _len)) goto LOOP2END;_state = 1;Current = _s.Substring(_i, _len);return true;STATE1: ;_i++;goto LOOP2BEGIN;LOOP2END: ;_len--;goto LOOP1BEGIN;LOOP1END: ;_state = -1;END: ;return false;}static IEnumerable<string> GetSubstrings(string s){for (var len = s.Length; len >= 1; len--)for (var i = 0; i <= s.Length - len; i++)yield return s.Substring(i, len);}public void Reset() { throw new NotImplementedException(); }public void Dispose() { }object IEnumerator.Current { get { return Current; } }public IEnumerator<string> GetEnumerator(){if(_state == 0) return this;else return new SubstringEnumerable(_s).GetEnumerator();}IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }}
内部実装(ローカル変数)• ローカル変数 → フィールドstatic IEnumerable<string> GetSubstrings(string s){for (var len = s.Length; len >= 1; len--)for (var i = 0; i <= s.Length - len; i++)yield return s.Substring(i, len);}class SubstringEnumerable : IEnumera{readonly string _s;int _len;int _i;int _state = 0;public SubstringEnumerable(strinpublic string Current { get; pripublic bool MoveNext(){if (_state == 1) goto STATE1if (_state == -1) goto END;
内部実装(yield return)• yield return → 状態記録、return、caseラベル• 中断と再開static IEnumerable<string> GetSubstrings(string s){for (var len = s.Length; len >= 1; len--)for (var i = 0; i <= s.Length - len; i++)yield return s.Substring(i, len);}if (_state == 1) goto STATE1;if (_state == -1) goto END;_state = 1;_len = _s.Length;LOOP1BEGIN: ;if (!(_len >= 1)) goto LOOP1END;_i = 0;LOOP2BEGIN: ;if (!(_i <= _s.Length - _len)) go_state = 1;Current = _s.Substring(_i, _len);return true;STATE1: ;_i++;goto LOOP2BEGIN;
内部実装(yield return)• yield returnの部分、意味合いとしては†switchで囲うyield return以外の場所はほぼ同じstatic IEnumerable<string> GetSubstrings(string s){for (var len = s.Length; len >= 1; len--)for (var i = 0; i <= s.Length - len; i++)yield return s.Substring(i, len);}yield return x;switch(_state){case 0:for (_len = _s.Length; _len >= 1; _len--)for (_i = 0; _i <= _s.Length - _len; _i++){_state = 1;Current = _s.Substring(_i, _len);return true;case 1:;}_state = -1;}_state = 1;Current = x;return true;case 1:;† forループ内にラベル張れないからさっきみたいな複雑なコードになるけども
内部実装(中断と再開)• yield returnの部分、意味合いとしては• 中断と再開yield return x;状態の記録_state = 1;Current = x;return true;case 1:;現在の値の保持復帰用のラベル
機械的な置き換えでできる• C++でも割と簡単class substring_iterator{private:const std::string& _s;int _len;int _i;std::string _current;int _state;public:substring_iterator(const std::string& s) : _s(s), _state(0) {}std::string current() { return _current; }bool move_next(){switch (_state){case 0:;for (_len = _s.length(); _len >= 1; _len--)for (_i = 0; _i <= _s.length() - _len; _i++){_state = 1;_current = _s.substr(_i, _len);return true;case 1:;}_state = -1;default:;}return false;}gotoとかcaseラベルの制限がゆるいので、むしろ簡単
機械的置き換えといえば• マクロを定義#define BEGIN_ITERATORswitch(_state){case 0:#define END_ITERATOR_state = -1;default:;}return false;#define YIELD(STATE, VALUE)_state = STATE;_current = VALUE;return true;case STATE:;
機械的置き換えといえば• マクロを使ってbool move_next(){BEGIN_ITERATORfor (_len = _s.length(); _len >= 1; _len--)for (_i = 0; _i <= _s.length() - _len; _i++){YIELD(1, _s.substr(_i, _len))}END_ITERATOR}
他の言語だと• 最近の言語は結構似た機能持ってる• ジェネレーター(generator)って呼ばれることが多い• 実装方式:• スタック丸ごとキャプチャしてしまうもの• 中断時に記録、再開時に復元• 式を継続渡しスタイル(CPS)に変換してしまうもの• スレッド使う• concurrent queue使って、yield returnのところでenqueue• さすがに性能的に論外だけども
ちなみに• コーディング面接で有名な某社の社員さん曰く、「 アルゴリズムの問題はかなりの割合、イテレーターを使うとあっさり書ける 」• 例に使ったのsubstring列挙も割とよく出てくるパターン• 中断と再開って大事
C++ 1y• C++にもジェネレーターが載るかも• C++ 17に向けて標準化案出てる• C++/CX向けの実装を元にMSが提案• async/awaitのついでsequence<int> range(int low, int high) resumable{for(int i = low; i <= high; ++i){yield i;}}
LINQ(Language IntegratedQuery)C# 3.0データ処理の直行化
LINQ• データ処理を言語統合• ほとんどはライブラリで実現• STLの<algorithm>とかBoost.RangeのAdaptersみたいなものvar source = new[] { 1, 2, 3, 4, 5 };var filtered = source.Where(x => x <= 3) // 1, 2, 3.Select(x => x * x); // 1, 4, 9System.Linq.Enumerable.WhereメソッドとSystem.Linq.Enumerable.Selectメソッドが呼ばれるだけ
データ処理の直行化• まあ、データの入力、加工、出力は分けましょうという話入力加工配列から{ 1, 2, 3, … }1, 2, 3 変換x => x * x 1, 4, 9データベースからSELECT x FROM tファイルからFile.Read…ユーザー入力からConsole.Read…1, 2, 3 選択x => x < 3 1, 21, 2, 3 グループ化x => x % 2 {1, 3},{2}出力配列にToArray()データベースにINSERT INTO tファイルにFile. Write…コンソールにConsole.Write…
データ処理の直行化• 掛け算を足し算にLパターンMパターンNパターン入力加工出力配列から{ 1, 2, 3, … }1, 2, 3 変換x => x * x 1, 4, 9配列にToArray()データベースからデータベースに1, 2, 3 選択SELECT 分けて作らないと L×M×N 通りのパターンx FROM tINSERT INTO tx => x < 3 1, 2分けて作ると L+M+N 通りファイルからファイルにFile.Read…File. Write…1, 2, 3 グループ化x => x % 2 {1, 3},ユーザー入力からコンソールに{2}Console.Read…Console.Write…
関連するC#の言語機能• C# 3.0• ラムダ式• 匿名型• 拡張メソッド
ラムダ式• 匿名関数を簡単に書けるsource.Select(x => x * x);(シーケンスの全要素を二乗)• C++のラムダ式と比べてシンプルなのは• 型推論がやりやすい• const&とかがない• ガベージ コレクションがあるし、変数キャプチャし放題
匿名型• 1か所でしか使わないような型は作らなくていいsource.GroupBy(p => new { p.X, p.Y });(XとYでグループ化)• immutableなクラスを自動生成• GetHashCode、等値比較、ToStringを完備
拡張メソッド• 静的メソッドを後置き記法で書けるsource.Select(x => x * x);同じ意味System.Linq.Enumerable.Select(source, x => x * x);C++でも関数オブジェクトに対する演算子オーバーロード似たことできなくはない• 単に語順を変えるだけ• 静的メソッドはpure functionである限り無害• pure = 状態を持たない同じ入力を与えたら常に同じ結果が帰ってくる
dynamicC# 4.0動的コード生成ダック タイピング
dynamic型• C# 4.0のdynamic型• 結構用途が限られてて• できること• 静的な型に対する動的コード生成• DLR言語との連携• できるけど過剰スペックなこと• JSONみたいなスキーマレスなデータ読み書き• できないこと• メタプログラミング• C#のスクリプト的実行
主なターゲットは静的な型• .NETの型情報に基づいた動的コード生成• IDynamicMetaObjectProviderを実装すれば型情報なくてもコード生成できるけども、あまりやる人いない• 利用例• 多重ディスパッチとか• ダック タイピングとか
多重ディスパッチ• 静的な型に対してclass Base { }class A : Base { }class B : Base { }
多重ディスパッチ• x, yの両方の型で動的に分岐• 仮想メソッドでは(素直には)できないstatic class Extensions{public static string Dispatch(this Base x, Base y){動的な呼び出しreturn (string)X((dynamic)x, (dynamic)y);}static string X(A x, A y) { return "A - A"; }static string X(A x, B y) { return "A - B"; }static string X(Base x, Base y) { return "others"; }}
多重ディスパッチ• 呼び出し例static void Main(){Dispatch(new A(),Dispatch(new A(),Dispatch(new B(),Dispatch(new B(),}newnewnewnewA());B());B());A());////////A - AA - Bothersothersstatic void Dispatch(Base x, Base y){Console.WriteLine(x.Dispatch(y));}
ダック タイピング• 静的な型に対してclass Point{public int X { get; set; }public int Y { get; set; }public override string ToString(){return "Point(" + X + ", " + Y + ")";}}
ダック タイピング• 同じ名前のメンバーを持つ別の型をまとめて処理static class Extensions{public static void CopyTo<T, U>(this T p, U q){dynamic x = p;dynamic y = q;y.X = x.X;X, Yを持つ任意y.Y = x.Y;の型に使える}}
ダック タイピング• 呼び出し例var p = new Point();new { X = 10, Y = 20 }.CopyTo(p);Console.WriteLine(p);
DLR連携• DLR (Dynamic Language Runtime)• 例: IronPythonvar py = IronPython.Hosting.Python.CreateEngine();dynamic p = py.Execute("['a', 'b', 1, 2]");for (var i = 0; i < 4; i++)Console.WriteLine(p[i]);• DLRは内部的に.NETの型を生成してるので内部実装的にはこれも「静的な型に対する動的コード生成」
dynamicの内部実装• コード生成結果実際にはobjectobject X(object x){if (_site1 == null)dynamic X(dynamic x){{_site1 = CallSite<Func<CallSite, oreturn x.X;Binder.GetMember(CSharpBinderF}動的コード生成new CSharpArgumentInfo[]用の情報{CSharpArgumentInfo.Create(これが本体}));}return _site1.Target(_site1, x);}
CallSite.Targetの中身• メソッドを動的コード生成してる• 生成したメソッドはキャッシュして持っておく(inline method cache)_site1.Targetの初期状態static object _anonymous(CallSite site, object x){return site.Targetを更新する処理}
CallSite.Targetの中身• メソッドを動的コード生成してる• 生成したメソッドはキャッシュして持っておく(inline method cache)メソッドXにPoint型のインスタンスを渡した後static object _anonymous(CallSite site, object x){1行追加if (x is Point) return ((Point)x).X;単なる型判定+キャストelse return site.Targetを更新する処理}• 同じ型に対して何度も呼ぶ分には高性能
CallSite.Targetの中身• メソッドを動的コード生成してる• 生成したメソッドはキャッシュして持っておく(inline method cache)さらに、メソッドXにVector3d型のインスタンスを渡した後static object _anonymous(CallSite site, object x){if (x is Point) return ((Point)x).X;if (x is Vector3D) return ((Vector3D)x).X; もう1行追加else return site.Targetを更新する処理}ちなみに、最近はスクリプト言語でも、内部的に型を作って、inline method cacheで高速化してる
“heavy” dynamic• 用途によっては高性能なものの…• 多くの場合、過剰スペック• できるけど過剰スペックな例• JSONみたいなスキーマレスなデータ読み書き• もっと”light-weight”なdynamicが必要(今のC#にはない。要望としてはある)例: 規約ベースの置き換えx.X;x.Get("X");x.M();x.Invoke("M");
できないこと• メンバー名がコンパイル時に既知でないとダメdynamic x = p;dynamic y = q;y.X = x.X;コンパイル時に既知y.Y = x.Y;• なのでメタプログラミングには使えない• そのためにはもっと低レイヤーなAPI使う• IL Emit• Expression Tree• Roslyn
コード生成API高級言語(C#)Roslyn†parse構文木式ツリー(System.Linq.Expressions)emitILGeneratorILJITネイティブコード† 新しいC#コンパイラーのコードネーム動的なコンパイルも可能
コード生成にかかる時間• あんまり動的にやりたくないある環境で、あるコードの生成結果の例かかった時間[ミリ秒]ILGenerator(JIT)39.89Expressions(emit→JIT)67.94Roslyn(parse→emit→JIT)4314倍遅い2桁遅い• 当たり前だけどparseは遅い• quoteほしい• できればコンパイル時生成でメタプログラミングしたい
async/awaitC# 5.0非同期処理
非同期処理しんどい• 普通に非同期処理やったらコールバック地獄• begin/end地獄• イベント地獄• then地獄(ContinueWith地獄)x.BeginX(args, state, ar =>x.XAsync(){.ContinueWith(t =>var result = x.EndX();{…var result = t.Result;x.XCompleted += (s, arg) =>});…{};非同期呼び出しが1回だからvar result = arg.Result;この程度で済んでる…});x.XAsync();
面倒な非同期処理の例• 複数の確認ダイアログ表示確認フローゲームでアイテムを合成します確認 1チェックレア アイテムですよ?Yes合成強化済みですよ?Yesもう強化限界ですよ?No確認 2チェックユーザーからの入力待ちも非同期処理YesNo確認 3チェックNo結果表示
同期処理if (Check1.IsChecked){var result = Dialog.ShowDialog("確認 1", "1つ目の確認作業");if (!result) return false;}if (Check2.IsChecked){var result = Dialog.ShowDialog("確認 2", "2つ目の確認作業");if (!result) return false;}if (Check3.IsChecked){var result = Dialog.ShowDialog("確認 3", "3つ目の確認作業");if (!result) return false;}return true;
非同期処理 (旧)if (Check1.IsChecked){Dialog.BeginShowDialog("確認 1", "1つ目の確認作業", result =>{if (!result){onComplete(false);return;}if (.Check2.IsChecked){Dialog.BeginShowDialog("確認 2", "2つ目の確認作業", result2 =>{if (!result2){onComplete(false);return;}if (Check3.IsChecked){Dialog.BeginShowDialog("確認 3", "3つ目の確認作業", result3 =>{onComplete(result3);});}elseonComplete(true);});}else if (Check3.IsChecked){Dialog.BeginShowDialog("確認 3", "3つ目の確認作業", result3 =>{onComplete(result3);});}elseonComplete(true);});}else if (Check2.IsChecked){Dialog.BeginShowDialog("確認 2", "2つ目の確認作業", result =>{if (!result){onComplete(false);return;}if (Check3.IsChecked){Dialog.BeginShowDialog("確認 3", "3つ目の確認作業", result3 =>{onComplete(result);});}elseonComplete(true);});}else if (Check3.IsChecked){Dialog.BeginShowDialog("確認 3", "3つ目の確認作業", result3 =>{onComplete(result3);});}elseonComplete(true);• 画面に収まるようにフォント サイズ調整• 4pt• ほんの84行ほど• ちなみに• 部分部分を関数化して多少は整理できる• ダイアログ3つだからまだこの程度で済む
非同期処理(C# 5.0)if (this.Check1.IsChecked ?? false){var result = await Dialog.ShowDialogAsync("確認 1", "1つ目の確認作業");if (!result) return false;}if (this.Check2.IsChecked ?? false){var result = await Dialog.ShowDialogAsync("確認 2", "2つ目の確認作業");if (!result) return false;}if (this.Check3.IsChecked ?? false){var result = await Dialog.ShowDialogAsync("確認 3", "3つ目の確認作業");if (!result) return false;}return true;• 同期処理と比べてawait演算子が増えただけ• ダイアログの数が増えても平気
イテレーターと似た仕組み• イテレーター(ジェネレーター)があれば、割と単純なラッパーで非同期処理も可能• 要は、「中断と再開」• 例えば、TypeScriptでは• 現状でもawaitのMS社内実装は持ってる• いまだと、生成されるJavaScriptが悲惨すぎて大変• EcmaScriptにジェネレーターが実装されてから、TypeScriptにawaitを追加する予定
参考: C#のイテレーター(再)• 中断と再開class MethodEnumerator : IEnumerator<int>{public int Current { get; private set; }private int _state = 0;public bool MoveNext(){switch (_state){case 0:状態の記録Current = 1;Current = 1;_state = 1;_state = 1;return true;中断return 1:case true;case 1: = 2;Current_state = 2;return true; 再開用のラベルIEnumerable<int> Method(){yield return 1;yield return 2;case 2:}}}}default:return false;
基本的な考え方• 概念としては イテレーター+継続呼び出し状態の記録async Task<int> Method(){var x = await task1;var y = await task2;}非同期処理が終_state = 1;わったら続きからif (!task1.IsCompleted)呼び出してもらう{task1.ContinueWith(a);return;中断}再開用のラベルcase 1:var x = task1.Result;結果の受け取り
実際の展開結果• 実際はもう少し複雑• Awaiterというものを介する(Awaitableパターン)_state = 1;var awaiter1 = task1.GetAwaiter();if (!awaiter1.IsCompleted){awaiter1.OnCompleted(a); • Awaiterを自作することで、awaitの挙動を変更可能return;}• Task以外もawait可能case 1:var x = awaiter1.GetResult();
C++ 1y• C++にもawaitが載るかも• C++ 17に向けて標準化案出てる• C++/CX向けの実装を元にMSが提案• 前述の通り、ついでにジェネレーターもfuture<void> f(stream str) async{shared_ptr<vector> buf = ...;int count = await str.read(512, buf);return count + 11;}
もう少し低レイヤーな話• Taskクラスasync Task<int> Method(){var x = await task1;var y = await task2;}_state = 1;if (!task1.IsCompleted){task1.ContinueWith(a);return;}case 1:var x = task1.Result;• スレッド機能だけあればいいわけじゃない• Task Pool、同期コンテキストとか
スレッド• 非同期処理の最も低レイヤーな部分• ただし、高負荷for (int i = 0; i < 1000; i++){var t = new Thread(Worker);t.Start();}1000個の処理を同時実行• 細々と大量の処理(タスク)をこなすには向かない• 切り替え(コンテキスト スイッチ)のコストが高すぎる
2種類のマルチタスクプリエンプティブ••••ハードウェア タイマーを使って強制割り込みOSが特権的にスレッド切り替えを行う利点: 公平(どんなタスクも等しくOSに制御奪われる)欠点: 高負荷(切り替えコストと使用リソース量)協調的※••••各タスクが責任を持って終了する1つのタスクが終わるまで次のタスクは始まらない利点: 低負荷欠点: 不公平(1タスクの裏切りが、全体をフリーズさせる)※cooperative
スレッド プール• スレッドを可能な限り使いまわす仕組み• プリエンプティブなスレッド数本の上に• 協調的なタスク キューを用意スレッド プールキュー新規タスクタスク1タスク2…タスクは一度キューに溜める数本のスレッドだけ用意空いているスレッドを探して実行(長時間空かない時だけ新規スレッド作成)ちなみに、std::futureはThread Poolな実装になってるはず
スレッド プールの向上• Work Stealing Queue• lock-free実装なローカル キュー• できる限りスレッド切り替えが起きないようにグローバルキュー①スレッドごとにキューを持つローカルキュー1ローカルキュー2スレッド1スレッド2②ローカル キューが空のとき、他のスレッドからタスクを奪取
シングル スレッド必須なもの• スレッド安全なコードは高コスト• いっそ、単一スレッド動作を前提に• 典型例はGUI• C#/.NETに限らずたいていのGUIフレームワークはシングル スレッド動作• 低レイヤーAPI(DirectXとかOpenGLとか)も、1つのスレッドからしか扱えない
典型例: UIスレッド• GUIは単一スレッド動作(UIスレッド)• ユーザーからの入力受け付け• 画面の更新ユーザーからの入力UIスレッドグラフィック他のスレッド更新OK処理中は応答不可他のスレッドからは更新不可
矛盾シングル スレッド推奨単一スレッドからしかUI更新できないOKそのスレッドを止めるとUIフリーズマルチ スレッド推奨
解決策1. スレッド プールで重たい処理2. UIスレッドに処理を戻してからUI更新UIスレッド他のスレッドTask.RunいったんUIスレッドにメッセージを渡す重たい処理Dispatcher.Invoke更新OK渡す役割を担うのがディスパッチャー※※dispatcher: 配送者他のGUIフレームワークだとevent queueとかhandlerとかいう名前で提供されたりするものの、やってることは一緒
おまけ: immutable• 並列処理といえばimmutableだけども• 書き換えが起こらないなら複数のスレッドで共有しても安全• この用途だと、C++のconstは不十分• あれは参照渡しを安全に行う用であって• 呼び出し元の側ではconstとは限らず、書き換わる可能性あり• あと、mutable修飾子を付ければconstなオブジェクトすら書き換えれる
Compiler as a ServiceFuture of C#, C# 6.0コンパイラーの内部データを活用
Compiler as a Service• 今、C#はコンパイラーをフルスクラッチで作り直してる• Code name “Roslyn”• C#実装のC#コンパイラー• コンパイラーの内部データを自由に使える
用途• C#スクリプティング• C#で設定ファイル書きたい(むしろXMLがいや)• アプリの再起動なしでロジック更新• ウェブ サービスで使う• (GitHubとか想像してもらって)コード リポジトリのインデックス化• オンラインIDE、ビルド、テスト• IDE連携
構文ハイライト• C#は文脈キーワードだらけメソッド名static IEnumerable<async> async(){var var = "var";クラス名var yield = new async();yield return yield;Func<string, Task<int>> async = async x =>{await Task.Delay(100);変数キーワードreturn int.Parse(x);};var await = async(var).GetAwaiter().GetResult();}
リアルタイム エラー検出• エラー検出タイミングがビルド時とか遅い• Visual Studioは常時やってる
コード補完• タイピングめんどくさい• 文法やライブラリ、いちいち覚えたくない
リファクタリング• 最初からきれいなコード書くのめんどくさい• でもほっときたくない
ということで• 今、コンパイラーに求められる要件• ソースコードのどこからどこまで(何行何列目)が何かという情報がとれる• 文脈に応じてソースコードを生成したり、書き替えたりできる• リアルタイム処理を必要とするので、パフォーマンスも求められる
実はこれまで• コンパイラー(パーサー)を2重開発してた• コンパイル用• IDE用• まして、サード パーティ製コード解析プラグインも含めると、3重開発• Java (EclipseとかIntelliJとか)でも• 「Eclipseが対応するまでJava 8プレビュー試せないや」
Clang• Clangはその辺りをゴールの1つに掲げてる• IDEで使う前提• リファクタリングに使いやすいデータ構造の構文木• インクリメンタル コンパイルとかもしやすい
IDE連携まで考えると• 簡単そうに見える文法ですら、実装コストかなり高い• 2重開発はそれだけ大変• だからIDEを信用しない/できない人も多い• IDE対応待ってられない/待ちたくない• “Roslyn”はそれを解消• C#に新機能を足しやすくなる• C# 6.0
C# 6.0 (予定)の例Primary Constructor / Property Expressionspublic class Point(int x, int y){public int X => x;immutableな型を作りやすくpublic int Y => y;}Declaration Expressions「式」で書けることの幅が広がるwhile ((var line = stream.ReadLine()) != null)line ...if ((var x = obj as Point) != null)x ...
以上。
まとめ• .NET Frameworkの基礎機能••••Garbage CollectionAppDomainメタデータ、JITPCL• C# 2.0~5.0… 6.0!• ジェネリック、イテレーター• LINQ、dynamic、async/await• Compiler as a Service

Recommended

PPTX
C# 8.0 非同期ストリーム
PDF
【Unite Tokyo 2019】Understanding C# Struct All Things
PDF
組み込みでこそC++を使う10の理由
PPTX
C# 8.0 null許容参照型
PPTX
async/await のしくみ
PDF
中3女子でもわかる constexpr
PDF
C++ マルチスレッドプログラミング
PDF
20分くらいでわかった気分になれるC++20コルーチン
 
PPTX
C# 9.0 / .NET 5.0
PPTX
C#とILとネイティブと
PPTX
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
PDF
オブジェクト指向エクササイズのススメ
PPTX
イベント駆動プログラミングとI/O多重化
PDF
ゲーム開発者のための C++11/C++14
PDF
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
PDF
目grep入門 +解説
PDF
オブジェクト指向の設計と実装の学び方のコツ
PDF
プログラムを高速化する話
PPTX
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
PDF
C++ マルチスレッド 入門
PPTX
Effective Modern C++ 勉強会 Item 22
PDF
ネットワーク ゲームにおけるTCPとUDPの使い分け
PDF
CRC-32
 
PDF
Unityでオニオンアーキテクチャ
PDF
C# ゲームプログラミングはホントにメモリのことに無頓着でいいの?
PDF
Unity開発で使える設計の話+Zenjectの紹介
PPTX
知らないと損するアプリ開発におけるStateMachineの活用法(full版)
PPTX
Linuxのsemaphoreとmutexを見る 
PPTX
C#/.NETがやっていること 第二版
PDF
できる!並列・並行プログラミング

More Related Content

PPTX
C# 8.0 非同期ストリーム
PDF
【Unite Tokyo 2019】Understanding C# Struct All Things
PDF
組み込みでこそC++を使う10の理由
PPTX
C# 8.0 null許容参照型
PPTX
async/await のしくみ
PDF
中3女子でもわかる constexpr
PDF
C++ マルチスレッドプログラミング
PDF
20分くらいでわかった気分になれるC++20コルーチン
 
C# 8.0 非同期ストリーム
【Unite Tokyo 2019】Understanding C# Struct All Things
組み込みでこそC++を使う10の理由
C# 8.0 null許容参照型
async/await のしくみ
中3女子でもわかる constexpr
C++ マルチスレッドプログラミング
20分くらいでわかった気分になれるC++20コルーチン
 

What's hot

PPTX
C# 9.0 / .NET 5.0
PPTX
C#とILとネイティブと
PPTX
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
PDF
オブジェクト指向エクササイズのススメ
PPTX
イベント駆動プログラミングとI/O多重化
PDF
ゲーム開発者のための C++11/C++14
PDF
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
PDF
目grep入門 +解説
PDF
オブジェクト指向の設計と実装の学び方のコツ
PDF
プログラムを高速化する話
PPTX
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
PDF
C++ マルチスレッド 入門
PPTX
Effective Modern C++ 勉強会 Item 22
PDF
ネットワーク ゲームにおけるTCPとUDPの使い分け
PDF
CRC-32
 
PDF
Unityでオニオンアーキテクチャ
PDF
C# ゲームプログラミングはホントにメモリのことに無頓着でいいの?
PDF
Unity開発で使える設計の話+Zenjectの紹介
PPTX
知らないと損するアプリ開発におけるStateMachineの活用法(full版)
PPTX
Linuxのsemaphoreとmutexを見る 
C# 9.0 / .NET 5.0
C#とILとネイティブと
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
オブジェクト指向エクササイズのススメ
イベント駆動プログラミングとI/O多重化
ゲーム開発者のための C++11/C++14
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
目grep入門 +解説
オブジェクト指向の設計と実装の学び方のコツ
プログラムを高速化する話
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
C++ マルチスレッド 入門
Effective Modern C++ 勉強会 Item 22
ネットワーク ゲームにおけるTCPとUDPの使い分け
CRC-32
 
Unityでオニオンアーキテクチャ
C# ゲームプログラミングはホントにメモリのことに無頓着でいいの?
Unity開発で使える設計の話+Zenjectの紹介
知らないと損するアプリ開発におけるStateMachineの活用法(full版)
Linuxのsemaphoreとmutexを見る 

Similar to C#や.NET Frameworkがやっていること

PPTX
C#/.NETがやっていること 第二版
PDF
できる!並列・並行プログラミング
PPTX
C#の書き方
PPTX
C# 7.2 with .NET Core 2.1
PPTX
Windows 8時代のアプリ開発
PDF
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
PPTX
今から始める、Windows 10&新.NETへの移行戦略
PDF
C#勉強会 ~ C#9の新機能 ~
PPTX
今から始める、Windows 10&新.NETへの移行戦略
PDF
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
PDF
C#勉強会
PDF
プログラミングNet framework3のお題
PPTX
.NET Core 2.x 時代の C#
PPTX
C#の書き方
PPT
20050903
PPTX
Deep Dive C# 6.0
PPTX
The evolution of c#
PPTX
Visual Studio による開発環境・プログラミングの進化
PPTX
090916 X D E V今だから理解する[
PPT
20010127
C#/.NETがやっていること 第二版
できる!並列・並行プログラミング
C#の書き方
C# 7.2 with .NET Core 2.1
Windows 8時代のアプリ開発
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
今から始める、Windows 10&新.NETへの移行戦略
C#勉強会 ~ C#9の新機能 ~
今から始める、Windows 10&新.NETへの移行戦略
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
C#勉強会
プログラミングNet framework3のお題
.NET Core 2.x 時代の C#
C#の書き方
20050903
Deep Dive C# 6.0
The evolution of c#
Visual Studio による開発環境・プログラミングの進化
090916 X D E V今だから理解する[
20010127

More from 信之 岩永

PPTX
非同期処理の基礎
PPTX
C#言語機能の作り方
PPTX
C# コンパイラーの書き換え作業の話
PPTX
Unicode文字列処理
PPTX
Unityで使える C# 6.0~と .NET 4.6
PPTX
Orange Cube 自社フレームワーク 2015/3
PPTX
.NET Compiler Platform
PPTX
C# 8.0 Preview in Visual Studio 2019 (16.0)
PPTX
プログラミング .NET Framework 第4版
PPTX
C# design note sep 2014
PPTX
広がる .Net
PPTX
Coding Interview
PPTX
C#マスコット(公開用)
PPTX
.NET vNext
PPTX
Modern .NET
PPTX
Code Contracts in .NET 4
PPTX
Anders Hejlsberg Q & A
PPTX
YouTube ライブ配信するようになった話
PPTX
それっぽく、適当に
非同期処理の基礎
C#言語機能の作り方
C# コンパイラーの書き換え作業の話
Unicode文字列処理
Unityで使える C# 6.0~と .NET 4.6
Orange Cube 自社フレームワーク 2015/3
.NET Compiler Platform
C# 8.0 Preview in Visual Studio 2019 (16.0)
プログラミング .NET Framework 第4版
C# design note sep 2014
広がる .Net
Coding Interview
C#マスコット(公開用)
.NET vNext
Modern .NET
Code Contracts in .NET 4
Anders Hejlsberg Q & A
YouTube ライブ配信するようになった話
それっぽく、適当に

C#や.NET Frameworkがやっていること


[8]ページ先頭

©2009-2025 Movatter.jp