Movatterモバイル変換


[0]ホーム

URL:


Takaaki Suzuki, profile picture
Uploaded byTakaaki Suzuki
PDF, PPTX4,854 views

Inside FastEnum

Event : .NET Conf in Tokyo 2019Date : 2019/10/27.NET Core 3.0 がリリースされさらなるパフォーマンスチューニングが行われましたが、Enum は依然として遅いままです。FastEnum はその苦痛を緩和する世界最速の Enum Utility ライブラリです。このドキュメントでは FastEnum の中で使われているテクニックや .NET Core 標準が遅い理由などについて解説し、速いコードを書くための一助となるようにします。

Embed presentation

Download as PDF, PPTX
.NET Conf in Tokyo 2019鈴木 孝明Inside FastEnum
Name鈴木 孝明 a.k.a @xin9leWorkApplication EngineerAwardMicrosoft MVPfor Developer TechnologiesWeb Sitehttps://xin9le.netAbout
Remote Worker @福井空港がない陸の孤島台風 19 号北陸新幹線復旧感謝!
速さは正義
という話をしましたhttps://www.slideshare.net/xin9le/dotnetperformancetips-170268354
狂気に満ちた世界 (その壱https://www.slideshare.net/neuecc/cedec-2018-c-c
狂気に満ちた世界 (その弐https://learning.unity3d.jp/3305/
.NET Core is SUPER fast !!
メモリ消費量-92%スループット+42%
超絶長編記事も公開
Enum is too slow…
The world fastest Enum (FastEnum)https://github.com/xin9le/FastEnum
System.Enum とほぼ同様の使用感var values = FastEnum.GetValues<Fruits>();var values = Enum.GetValues(typeof(Fruits)) as Fruits[];var names = FastEnum.GetNames<Fruits>();var names = Enum.GetNames(typeof(Fruits));var parse = FastEnum.Parse<Fruits>("Apple");var parse = Enum.Parse<Fruits>("Apple");var defined = FastEnum.IsDefined(Fruits.Lemon);var defined = Enum.IsDefined(typeof(Fruits), Fruits.Lemon);
フィールドの値/名前などを一纏めに値/名前のペアって案外使うのに、ペアを作る処理は地味に面倒Member<T>// フィールド情報public sealed class Member<T>where T : struct, Enum{public T Value { get; }public string Name { get; }public FieldInfo FieldInfo { get; }public EnumMemberAttribute EnumMemberAttribute { get; }}// 超高速で簡単な取得var xs = FastEnum.GetMembers<Fruits>();var x1 = FastEnum.GetMember(Fruits.Apple);var x2 = Fruits.Apple.ToMember();
フィールドに複数の名前を付けられる[EnumMember] だと AllowMultiple = false なので不便Grani 社内で使われていた便利機能のひとつLabel 属性// インデックス指定で取得できるvar a = Fruits.Apple.GetLabel(0); // 🍎var b = Fruits.Apple.GetLabel(1); // りんご// こんな定義があったとしてpublic enum Fruits{[Label("🍎", 0)][Label(“りんご", 1)]Apple,}
速くなったと言われる .NET Core 3.0 なのに、なぜ!Why standard enum is slow?
RuntimeType.GenericCache を使ってるそこまでは良いのだけど、キャッシュの持ち方がよくないulong[] / string[] を持つだけで、それ以上のトリックがない都度 Reflection している箇所もEnum.GetName / Enum.IsDefined などなどキャッシュとは何だったのか...中途半端なキャッシュ
ほぼ必ず object 型を経由するNon Generics な Array とか Enum.ToObject とかを普通に使うulong で持っていたものを有効活用しないとか超クールParse<T> / TryParse<T>はまともSystem.Enum で Generics 版が使えるときは積極的に使う※ .NET Core に限る※ .NET Framework の実装は残念過ぎるBox / Unbox の雨霰
.NET Core is SUPER fast ??
高速化のアプローチとちょっとした工夫Why FastEnum is fast?
Static Type Cachingpublic static class FastEnum{public static IReadOnlyList<T> GetValues<T>()where T : struct, Enum=> Cache<T>.Values; // キャッシュを直接参照// 静的 Generics 型のフィールドにキャッシュを持つprivate static class Cache<T>where T : struct, Enum{public static readonly T[] Values;static Cache()=> Values = (T[])Enum.GetValues(typeof(T));}}T 型ごとに別の型扱い
呼び出しコスト ≒ 0型をキーにした辞書から Lookup するよりもずっと速いBenchmarkDotNet が「計測できない」と音を上げるレベル静的コンストラクタで事前計算静的コンストラクタはスレッドセーフが保証されているロックフリーにできるので、呼び出しコスト低減に大きく寄与Static Type Caching
Non Generics API は box 化を避けられないGenerics API だけでも大抵のケースに耐えられるGenerics API のみをサポート// .NET Core (Box 化する)var a = Enum.GetValues(typeof(Fruits));var b = Enum.GetName(typeof(Fruits), Fruits.Banana);var c = (Fruits)Enum.Parse(typeof(Fruits), "Apple");var d = Enum.IsDefined(typeof(Fruits), Fruits.Lemon);// FastEnum (一切 Box 化しない)var a = FastEnum.GetValues<Fruits>();var b = FastEnum.GetName(Fruits.Banana);var c = FastEnum.Parse<Fruits>("Apple");var d = FastEnum.IsDefined(Fruits.Lemon);
[Flags] な列挙型を Parse する機能カンマが入っているかどうかを算出するコストが大きい滅多に使わない機能を落として大多数を救う方が理に適っているカンマ区切り文字列は非サポート// こんな定義があるとき[Flags]enum Fruits{Apple = 1,Lemon = 2,Melon = 4,}// System.Enum はカンマ区切り文字を Parse できるvar value = Enum.Parse<Fruits>("Apple, Melon");Console.WriteLine((int)value); // 5
列挙型の値の連続性を利用値が連続しているなら最大/最小範囲に入っているかを比較辞書の ContainsKey をするより範囲チェックの方が何倍も高速IsDefined<T>(value); の最適化// 連続した値の列挙型enum Fruits{Apple = 1,Lemon, // 2Melon, // 3Banana, // 4}// こんな感じのイメージで判定すると速い// 連続しているかどうかは事前に判定してキャッシュpublic static bool IsDefined<T>(T value)where T : struct, Enum=> IsContinuous? MinValue <= value && value <= MaxValue: Values.ContainsKey(value);
“123”, “Apple” をどう判別/解析するか「1 文字目が数字か +/-」の場合は値で解析するParse<T>(“value/name”); の最適化public static bool TryParse<T>(string value, out T result)where T : struct, Enum{// フィールド名は数字/特殊記号で始められない仕様を利用return IsNumeric(value[0])? TryParseByValue(value, out result): TryParseByName(value, out result);static bool IsNumeric(char c)=> char.IsDigit(c) || c == '-' || c == '+';}
string.Equals(OrdinalIgnoreCase) が最速StringComparison.InvariantCultureIgnoreCase より 4 倍速い大小無視の文字列比較
キーの特殊化で EqualityComparer を廃止GetHashCode(); と Equals(); を直呼び出しにするハックhttp://engineering.grani.jp/entry/2017/07/28/145035温もりティ溢れる手作り辞書// 正味たった 2 行だけの違い// 最終的にこの差がベンチマークに効いてくるvar hash = EqualityComparer<int>.Default.GetHashCode(key);var hash = key.GetHashCode(); // fasterif (EqualityComparer<TKey>.Default.Equals(next.Key, key))if (next.Key == key) // faster
他にもある細々したテクニックとかポイントOther tips and tricks
列挙型を等値/大小で比較する// 具象型の場合はできるけれど...public static void Compare(Fruits left, Fruits right){var a = left == right; // OKvar b = left <= right; // OK}// Enum 制約をしていても Generics 型だとできない!public static void Compare<T>(T left, T right)where T : struct, Enum{var a = left == right; // コンパイルエラーvar b = left <= right; // コンパイルエラーvar c = EqualityComparer<T>.Default.Equals(left, right); // OK}なんとか解決したい
System.Runtime.CompilerServices.Unsafeunsafe オプションを使わずに unsafe なことをする悪い子😈Unsafe.As を使った強制型変換public static void Compare<T>(T left, T right)where T : struct, Enum{// ref を使った型変換 = 同一メモリ領域を別の型として参照ref var l = ref Unsafe.As<T, int>(ref left);ref var r = ref Unsafe.As<T, int>(ref right);var a = l == r; // OKvar b = l <= r; // OK}
UnderlyingType の TryParse に委譲同一メモリ領域を参照した強制型変換なので、できちゃう😈Unsafe.As のちょっとズルい使い方internal sealed class Int32Operation<T> : IUnderlyingOperation<T>where T : struct, Enum{public bool TryParse(string text, out T result){// x に書き込めば result にも書き込まれたことになるresult = default;ref var x = ref Unsafe.As<T, int>(ref result);return int.TryParse(text, out x);}}
FastEnum が唯一勝てなかったメソッド引数が Enum なので呼び出すだけで box 化して超遅そうだが…自作したものより 200 倍以上高速でアロケーションもない// 特殊な最適化がかかってる (たぶん[Intrinsic]public bool HasFlag(Enum flag){}Enum.HasFlag の脅威的性能
ReadOnlyCollection は foreach が超遅いStruct Enumerator を利用した配列の読み取り専用 wrapper で解決https://ufcpp.net/blog/2018/12/howtoenumerate/ReadOnlyArraypublic sealed class ReadOnlyArray<T> : IReadOnlyList<T>{private readonly T[] source;public ReadOnlyArray(T[] source) => this.source = source;public Enumerator GetEnumerator() => new Enumerator(this.source);public struct Enumerator : IEnumerator<T> { /* 省略 */ }// 以下略...}
今日、これだけは持って帰りましょう!Conclusion
速さは正義ちょっとした工夫で案外メチャクチャ速くなる!速いコードを書くひとつの参考になれば幸いです本当は FastEnum は存在しない方が良い標準が速ければ最高だし、そうあってほしい.NET Core 頑張れFastEnum is SUPER fast !!
Enjoy high performance programming using C#!!Thank you

Recommended

PDF
【Unite Tokyo 2019】Understanding C# Struct All Things
PDF
A Brief History of UniRx/UniTask, IUniTaskSource in Depth
PDF
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
PDF
ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法
PPTX
Unityネイティブプラグインマニアクス #denatechcon
 
PDF
Memory Management of C# with Unity Native Collections
PDF
Unity開発で使える設計の話+Zenjectの紹介
PDF
怖くないSpring Bootのオートコンフィグレーション
PDF
今日からできる!簡単 .NET 高速化 Tips
PDF
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
PDF
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
PDF
The Usage and Patterns of MagicOnion
PDF
ライブラリ作成のすゝめ - 事例から見る個人OSS開発の効能
PPTX
C#で速度を極めるいろは
PDF
Unityではじめるオープンワールド制作 エンジニア編
PPTX
Deep-Dive into Scriptable Build Pipeline
PDF
Unityでパフォーマンスの良いUIを作る為のTips
PPTX
Spanner移行について本気出して考えてみた
PDF
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
PDF
LogbackからLog4j 2への移行によるアプリケーションのスループット改善 ( JJUG CCC 2021 Fall )
PDF
こわくない Git
PDF
Spring bootでweb バリデート編
 
PPTX
第六回渋谷Java Java8のJVM監視を考える
PDF
UE4でマルチプレイヤーゲームを作ろう
PDF
Unityでオニオンアーキテクチャ
PPTX
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
 
PPTX
Redisの特徴と活用方法について
PDF
インタフェース完全に理解した
PPTX
最速C# 7.x
PPTX
C# 9.0 / .NET 5.0

More Related Content

PDF
【Unite Tokyo 2019】Understanding C# Struct All Things
PDF
A Brief History of UniRx/UniTask, IUniTaskSource in Depth
PDF
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
PDF
ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法
PPTX
Unityネイティブプラグインマニアクス #denatechcon
 
PDF
Memory Management of C# with Unity Native Collections
PDF
Unity開発で使える設計の話+Zenjectの紹介
PDF
怖くないSpring Bootのオートコンフィグレーション
【Unite Tokyo 2019】Understanding C# Struct All Things
A Brief History of UniRx/UniTask, IUniTaskSource in Depth
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法
Unityネイティブプラグインマニアクス #denatechcon
 
Memory Management of C# with Unity Native Collections
Unity開発で使える設計の話+Zenjectの紹介
怖くないSpring Bootのオートコンフィグレーション

What's hot

PDF
今日からできる!簡単 .NET 高速化 Tips
PDF
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
PDF
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
PDF
The Usage and Patterns of MagicOnion
PDF
ライブラリ作成のすゝめ - 事例から見る個人OSS開発の効能
PPTX
C#で速度を極めるいろは
PDF
Unityではじめるオープンワールド制作 エンジニア編
PPTX
Deep-Dive into Scriptable Build Pipeline
PDF
Unityでパフォーマンスの良いUIを作る為のTips
PPTX
Spanner移行について本気出して考えてみた
PDF
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
PDF
LogbackからLog4j 2への移行によるアプリケーションのスループット改善 ( JJUG CCC 2021 Fall )
PDF
こわくない Git
PDF
Spring bootでweb バリデート編
 
PPTX
第六回渋谷Java Java8のJVM監視を考える
PDF
UE4でマルチプレイヤーゲームを作ろう
PDF
Unityでオニオンアーキテクチャ
PPTX
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
 
PPTX
Redisの特徴と活用方法について
PDF
インタフェース完全に理解した
今日からできる!簡単 .NET 高速化 Tips
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
The Usage and Patterns of MagicOnion
ライブラリ作成のすゝめ - 事例から見る個人OSS開発の効能
C#で速度を極めるいろは
Unityではじめるオープンワールド制作 エンジニア編
Deep-Dive into Scriptable Build Pipeline
Unityでパフォーマンスの良いUIを作る為のTips
Spanner移行について本気出して考えてみた
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
LogbackからLog4j 2への移行によるアプリケーションのスループット改善 ( JJUG CCC 2021 Fall )
こわくない Git
Spring bootでweb バリデート編
 
第六回渋谷Java Java8のJVM監視を考える
UE4でマルチプレイヤーゲームを作ろう
Unityでオニオンアーキテクチャ
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
 
Redisの特徴と活用方法について
インタフェース完全に理解した

Similar to Inside FastEnum

PPTX
最速C# 7.x
PPTX
C# 9.0 / .NET 5.0
PPTX
C#言語機能の作り方
PDF
F#によるFunctional Programming入門
PDF
知って得するC#
PPTX
C# 8.0 Preview in Visual Studio 2019 (16.0)
PPTX
メタな感じのプログラミング(プロ生 + わんくま 071118)
PDF
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
PDF
C#勉強会 ~ C#9の新機能 ~
PDF
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
PPTX
C# 8
PPTX
C# design note sep 2014
PPTX
.NET Core 2.x 時代の C#
PPTX
Effective java 輪読会 第6章 項目32-34
PPTX
C# 7 Current Status
PPTX
Live Coding で学ぶ C# 7
PPT
CLR/H No.35-2
PDF
20141129-dotNet2015
PPTX
Deep Dive C# 6.0
PDF
これからの「言語」の話をしよう ―― 未来を生きるためのツール
最速C# 7.x
C# 9.0 / .NET 5.0
C#言語機能の作り方
F#によるFunctional Programming入門
知って得するC#
C# 8.0 Preview in Visual Studio 2019 (16.0)
メタな感じのプログラミング(プロ生 + わんくま 071118)
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
C#勉強会 ~ C#9の新機能 ~
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
C# 8
C# design note sep 2014
.NET Core 2.x 時代の C#
Effective java 輪読会 第6章 項目32-34
C# 7 Current Status
Live Coding で学ぶ C# 7
CLR/H No.35-2
20141129-dotNet2015
Deep Dive C# 6.0
これからの「言語」の話をしよう ―― 未来を生きるためのツール

More from Takaaki Suzuki

PDF
C# における Redis 徹底活用
PPTX
4 Colors Othello’s Algorithm
PDF
C#のココが好き!
PDF
Friendly
PDF
Twilioと.NET
PDF
5 分で学ぶ Interpolated String Handler
PDF
酒の肴はC# vNext
PPTX
Tetris Algorithm
PDF
SignalR Tune-up
PDF
Async History in .NET
PDF
DeclarativeSql
PPTX
Sharing Deep Dive
PDF
4 Colors Othello’s Algorithm @仙台 IT 文化祭 2017
PPTX
C# 7 New Features
PDF
30min Serverless xTuber
PDF
Universal Appとは? -デバイスに依存しないアプリケーション開発-
PDF
Programmer's Brain
PDF
WPF Interoperability
PDF
What's MVP
PDF
Sevens Algorithm
C# における Redis 徹底活用
4 Colors Othello’s Algorithm
C#のココが好き!
Friendly
Twilioと.NET
5 分で学ぶ Interpolated String Handler
酒の肴はC# vNext
Tetris Algorithm
SignalR Tune-up
Async History in .NET
DeclarativeSql
Sharing Deep Dive
4 Colors Othello’s Algorithm @仙台 IT 文化祭 2017
C# 7 New Features
30min Serverless xTuber
Universal Appとは? -デバイスに依存しないアプリケーション開発-
Programmer's Brain
WPF Interoperability
What's MVP
Sevens Algorithm

Inside FastEnum


[8]ページ先頭

©2009-2025 Movatter.jp