Work
C#
Unity
Private
http://neue.cc/
@neuecc
https://github.com/neuecc/UniRx
using
ZeroFormatter
秘訣は...
評価を遅らせる
無限大高速なシリアライザ
https://github.com/neuecc/ZeroFormatter/
シリアライズも速い
無限大高速なシリアライザ
https://github.com/neuecc/ZeroFormatter/
シリアライズも速い
Benchmark
本当に速いの?
はい。
辻ベンチマーク
Serialization Process
例えばint(999)をbyte[]にシリアライズ
var bytes = BitConverter.GetBytes(999);
unsafe
{
var bytes = new byte[4];
fixed (byte* ptr = byt...
// ふつーのシリアライザのAPIの例
byte[] Serialize<T>(T obj)
{
// 1. 内部での書き込みストリーム作りのためにnew MemoryStream
using(var stream = new MemorySt...
// ふつーのシリアライザのAPIの例
byte[] Serialize<T>(T obj)
{
// 1. 内部での書き込みストリーム作りのためにnew MemoryStream
using(var stream = new MemorySt...
// ZeroFormatterのばやい
byte[] Serialize<T>(T obj)
{
// 1. Static変数からの最速での子シリアライザの取得
var formatter = Formatter<DefaultResolve...
// ZeroFormatterのばやい
byte[] Serialize<T>(T obj)
{
// 1. Static変数からの最速での子シリアライザの取得
var formatter = Formatter<DefaultResolve...
1階層だけの抽象化
public abstract class Formatter<TTypeResolver, T>
where TTypeResolver : ITypeResolver, new()
{
public abstract i...
internal class Int32ArrayFormatter : Formatter<Int32[]>
{
public override int Serialize(ref byte[] bytes, int offset, Int3...
Conclusion
バイナリだから速いということはない
シリアライザのパフォーマンスは実装が大事
よく出来たJSONシリアライザはその辺のバイナリ系より速い
(実際 Jil はめちゃくちゃすごくよく出来た実装)
汎用シリアライザのチューニング可能箇所は無数
特にE...
C#における潮流の変化
競合相手の変化、GoなどのBetter C勢と戦わなければならない
富豪的プログラミングでOKで済ませられる局面は、特にフレーム
ワークレイヤーでは厳しくなってきている(今まで以上に、ね)
言語(C# 7.0)とフレーム...
ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法
ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法
ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法
ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法
ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法
Próxima SlideShare
Cargando en…5
×

ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法

25.003 visualizaciones

Publicado el

https://github.com/neuecc/ZeroFormatter

Publicado en: Tecnología
0 comentarios
4 recomendaciones
Estadísticas
Notas
  • Sé el primero en comentar

Sin descargas
Visualizaciones
Visualizaciones totales
25.003
En SlideShare
0
De insertados
0
Número de insertados
23.891
Acciones
Compartido
0
Descargas
8
Comentarios
0
Recomendaciones
4
Insertados 0
No insertados

No hay notas en la diapositiva.

ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法

  1. 1. Work C# Unity Private http://neue.cc/ @neuecc https://github.com/neuecc/UniRx
  2. 2. using
  3. 3. ZeroFormatter
  4. 4. 秘訣は...
  5. 5. 評価を遅らせる
  6. 6. 無限大高速なシリアライザ https://github.com/neuecc/ZeroFormatter/ シリアライズも速い
  7. 7. 無限大高速なシリアライザ https://github.com/neuecc/ZeroFormatter/ シリアライズも速い
  8. 8. Benchmark
  9. 9. 本当に速いの?
  10. 10. はい。
  11. 11. 辻ベンチマーク
  12. 12. Serialization Process
  13. 13. 例えばint(999)をbyte[]にシリアライズ var bytes = BitConverter.GetBytes(999); unsafe { var bytes = new byte[4]; fixed (byte* ptr = bytes) { *((int*)ptr) = 999; } }
  14. 14. // ふつーのシリアライザのAPIの例 byte[] Serialize<T>(T obj) { // 1. 内部での書き込みストリーム作りのためにnew MemoryStream using(var stream = new MemoryStream()) // 2. データ生成時の内部ステートを保持するためのWriterのnew var writer = new XxxWriter(stream); // 3. Int用子シリアライザの取得あるいはprimitiveの場合はswitch var serializer = serializerCacheDictionary[typeof(T)]; // 4. (意外と内部では入ってることがある)objectへのボクシング serializer.WriteObject(writer, (object)obj); // 5. 可変長整数へのエンコード if(x <10) write... else if(x < 150) write... // 6. WriteByte呼び出しの連打(内部では幾つかのifやインクリメント) stream.WriteByte(byte >> 0); stream.WriteByte(byte >> 8) ... // 7. MemoryStreamのToArrayはbyte[]コピー memoryStream.ToArray(); }
  15. 15. // ふつーのシリアライザのAPIの例 byte[] Serialize<T>(T obj) { // 1. 内部での書き込みストリーム作りのためにnew MemoryStream using(var stream = new MemoryStream()) // 2. データ生成時の内部ステートを保持するためのWriterのnew var writer = new XxxWriter(stream); // 3. Int用子シリアライザの取得あるいはprimitiveの場合はswitch var serializer = serializerCacheDictionary[typeof(T)]; // 4. (意外と内部では入ってることがある)objectへのボクシング serializer.WriteObject(writer, (object)obj); // 5. 可変長整数へのエンコード if(x <10) write... else if(x < 150) write... // 6. WriteByte呼び出しの連打(内部では幾つかのifやインクリメント) stream.WriteByte(byte >> 0); stream.WriteByte(byte >> 8) ... // 7. MemoryStreamのToArrayはbyte[]コピー memoryStream.ToArray(); } そりゃ遅い!!! し、ゴミも発生しまくる
  16. 16. // ZeroFormatterのばやい byte[] Serialize<T>(T obj) { // 1. Static変数からの最速での子シリアライザの取得 var formatter = Formatter<DefaultResolver, T>.Default; // 2. 当然ボクシングは全くなく、内部構造も全てジェネリクスで統一されてる formatter.Serialize(T value); // 3. 長さが既知の場合は長さを取って生成できる var bytes = new byte[formatter.GetLength()]; // 4. バイト配列に直接書く(WriteInt32の中身は *((int*)b) = value; だけ) BinaryUtil.WriteInt32(ref bytes, value); // 5. 出来たバイト配列をそのまま返すだけ return bytes; }
  17. 17. // ZeroFormatterのばやい byte[] Serialize<T>(T obj) { // 1. Static変数からの最速での子シリアライザの取得 var formatter = Formatter<DefaultResolver, T>.Default; // 2. 当然ボクシングは全くなく、内部構造も全てジェネリクスで統一されてる formatter.Serialize(T value); // 3. 長さが既知の場合は長さを取って生成できる var bytes = new byte[formatter.GetLength()]; // 4. バイト配列に直接書く(WriteInt32の中身は *((int*)b) = value; だけ) BinaryUtil.WriteInt32(ref bytes, value); // 5. 出来たバイト配列をそのまま返すだけ return bytes; } 汎用シリアライザながら 理論上最速とほぼ同等! ゴミも発生しない!
  18. 18. 1階層だけの抽象化 public abstract class Formatter<TTypeResolver, T> where TTypeResolver : ITypeResolver, new() { public abstract int? GetLength(); public abstract int Serialize(ref byte[] bytes, int offset, T value); public abstract T Deserialize(ref byte[] bytes, int offset, out int byteSize); }
  19. 19. internal class Int32ArrayFormatter : Formatter<Int32[]> { public override int Serialize(ref byte[] bytes, int offset, Int32[] value) { var writeSize = value.Length * 4; BinaryUtil.EnsureCapacity(ref bytes, offset, writeSize + 4); BinaryUtil.WriteInt32Unsafe(ref bytes, offset, value.Length); Buffer.BlockCopy(value, 0, bytes, offset + 4, writeSize); return writeSize + 4; } } // 例えばint[]の場合、普通はintの要素一個一個を処理するコードになる for (int i = 0; i < values.Length; i++) { stream.Write(serialize(values[i])); }
  20. 20. Conclusion
  21. 21. バイナリだから速いということはない シリアライザのパフォーマンスは実装が大事 よく出来たJSONシリアライザはその辺のバイナリ系より速い (実際 Jil はめちゃくちゃすごくよく出来た実装) 汎用シリアライザのチューニング可能箇所は無数 特にEnumは取扱注意で、語ると長くなりまうす それら無数に存在する全てを潰しきったのがZeroFormatter (パフォーマンス優先で潰し切ることが可能な設計になってる) というわけで、なので自信もってC#最速だといえます
  22. 22. C#における潮流の変化 競合相手の変化、GoなどのBetter C勢と戦わなければならない 富豪的プログラミングでOKで済ませられる局面は、特にフレーム ワークレイヤーでは厳しくなってきている(今まで以上に、ね) 言語(C# 7.0)とフレームワーク両面で性能に強い意識が働いている 抽象化をいかに薄くするかや、LINQを使わないということはLINQ をどう使うか、と同じぐらいの重要性を持った選択肢になってくる Corefxlab https://github.com/dotnet/corefxlab/ System.Slices - より効率的な配列やメモリ相互変換の取扱い System.IO.Pipelines - より高速なStream抽象 System.Text.Utf8 - UTF8変換へのオーバーヘッド低減

×