Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

河合 宜文 / Kawai Yoshifumi / @neuecc Cysharp, Inc. Cygames C#大統一理論 C#

Slide 3

Slide 3 text

#1 Binary Serializer in .NET https://github.com/neuecc/MessagePack-CSharp

Slide 4

Slide 4 text

Zero encoding extreme fast binary serializer https://github.com/Cysharp/MemoryPack/ 究極的

Slide 5

Slide 5 text

1リクエストに1000回実行することはある

Slide 6

Slide 6 text

バッチやクライアントアプリケーションでも

Slide 7

Slide 7 text

Incremental Source Generator

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No.

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

Serialize/MemoryPackWriter

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

public void WriteUnmanaged(scoped in T1 value1) where T1 : unmanaged { var size = Unsafe.SizeOf(); ref var spanRef = ref GetSpanReference(size); Unsafe.WriteUnaligned(ref spanRef, value1); Advance(size); } 書き込み用バッファー管理 public ref partial struct MemoryPackWriter where TBufferWriter : IBufferWriter { ref TBufferWriter bufferWriter; ref byte bufferReference; int bufferLength; ref byte GetSpanReference(int sizeHint); void Advance(int count); public MemoryPackWriter(ref TBufferWriter writer) } public interface System.Buffers.IBufferWriter { Span GetSpan(int sizeHint = 0); void Advance(int count); }

Slide 15

Slide 15 text

public void WriteUnmanaged(scoped in T1 value1) where T1 : unmanaged { var size = Unsafe.SizeOf(); ref var spanRef = ref GetSpanReference(size); Unsafe.WriteUnaligned(ref spanRef, value1); Advance(size); } 書き込み用バッファー管理 public ref partial struct MemoryPackWriter where TBufferWriter : IBufferWriter { ref TBufferWriter bufferWriter; ref byte bufferReference; int bufferLength; ref byte GetSpanReference(int sizeHint); void Advance(int count); public MemoryPackWriter(ref TBufferWriter writer) } public interface System.Buffers.IBufferWriter { Span GetSpan(int sizeHint = 0); void Advance(int count); }

Slide 16

Slide 16 text

public void WriteUnmanaged(scoped in T1 value1) where T1 : unmanaged { var size = Unsafe.SizeOf(); ref var spanRef = ref GetSpanReference(size); Unsafe.WriteUnaligned(ref spanRef, value1); Advance(size); } 書き込み用バッファー管理 public ref partial struct MemoryPackWriter where TBufferWriter : IBufferWriter { ref TBufferWriter bufferWriter; ref byte bufferReference; int bufferLength; ref byte GetSpanReference(int sizeHint); void Advance(int count); public MemoryPackWriter(ref TBufferWriter writer) } public interface System.Buffers.IBufferWriter { Span GetSpan(int sizeHint = 0); void Advance(int count); }

Slide 17

Slide 17 text

public void WriteUnmanaged(scoped in T1 value1) where T1 : unmanaged { var size = Unsafe.SizeOf(); ref var spanRef = ref GetSpanReference(size); Unsafe.WriteUnaligned(ref spanRef, value1); Advance(size); } 書き込み用バッファー管理 public ref partial struct MemoryPackWriter where TBufferWriter : IBufferWriter { ref TBufferWriter bufferWriter; ref byte bufferReference; int bufferLength; ref byte GetSpanReference(int sizeHint); void Advance(int count); public MemoryPackWriter(ref TBufferWriter writer) } public interface System.Buffers.IBufferWriter { Span GetSpan(int sizeHint = 0); void Advance(int count); }

Slide 18

Slide 18 text

書き込み用バッファー管理 public ref partial struct MemoryPackWriter where TBufferWriter : IBufferWriter { ref TBufferWriter bufferWriter; ref byte bufferReference; int bufferLength; ref byte GetSpanReference(int sizeHint); void Advance(int count); public MemoryPackWriter(ref TBufferWriter writer) }

Slide 19

Slide 19 text

public static partial class MemoryPackSerializer { public static void Serialize(in TBufferWriter bufferWriter, in T? value) public static byte[] Serialize(in T? value) public static ValueTask SerializeAsync(Stream stream, T? value) } var writer = new MemoryPackWriter(ref bufferWriter); writer.WriteValue(value); writer.Flush();

Slide 20

Slide 20 text

public static partial class MemoryPackSerializer { public static void Serialize(in TBufferWriter bufferWriter, in T? value) public static byte[] Serialize(in T? value) public static ValueTask SerializeAsync(Stream stream, T? value) } var bufferWriter = ReusableLinkedArrayBufferWriterPool.Rent(); var writer = new MemoryPackWriter(ref bufferWriter); writer.WriteValue(value); writer.Flush(); await bufferWriter.WriteToAndResetAsync(stream); return bufferWriter.ToArrayAndReset();

Slide 21

Slide 21 text

byte[] byte[] byte[] ArrayPool.Shared.Rent GetSpan() public sealed class ReusableLinkedArrayBufferWriter : IBufferWriter { List buffers; } struct BufferSegment { byte[] buffer; int written; }

Slide 22

Slide 22 text

IBufferWriterを優先する

Slide 23

Slide 23 text

Deserialize/MemoryPackReader

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

public ref partial struct MemoryPackReader { ReadOnlySequence bufferSource; ref byte bufferReference; int bufferLength; ref byte GetSpanReference(int sizeHint); void Advance(int count); public MemoryPackReader(in ReadOnlySequence bufferSource) public MemoryPackReader(ReadOnlySpan buffer) } 読み込み用バッファー管理

Slide 26

Slide 26 text

連結されたbyte[]、のようなもの

Slide 27

Slide 27 text

性能は同期バッファと非同期読み書きで決まる Streaming処理は別の機構で行う

Slide 28

Slide 28 text

Optimize for All Types

Slide 29

Slide 29 text

C#の配列は要素がunmanaged型(参照型を含まな いstruct)の場合、全て直列に並ぶ var srcLength = Unsafe.SizeOf() * value.Length; var allocSize = srcLength + 4; ref var dest = ref GetSpanReference(allocSize); ref var src = ref Unsafe.As(ref GetArrayDataReference(value)); Unsafe.WriteUnaligned(ref dest, value.Length); Unsafe.CopyBlockUnaligned(ref Unsafe.Add(ref dest, 4), ref src, (uint)srcLength); Advance(allocSize);

Slide 30

Slide 30 text

Vector3[]など複合型になればなるほど有利

Slide 31

Slide 31 text

public sealed class ListFormatter : MemoryPackFormatter> { public override void Serialize( ref MemoryPackWriter writer, scoped ref List? value) { if (value == null) { writer.WriteNullCollectionHeader(); return; } var span = CollectionsMarshal.AsSpan(value); var formatter = GetFormatter(); WriteCollectionHeader(span.Length); for (int i = 0; i < span.Length; i++) { formatter.Serialize(ref this, ref span[i]); } } }

Slide 32

Slide 32 text

public override void Deserialize(ref MemoryPackReader reader, scoped ref List? value) { if (!reader.TryReadCollectionHeader(out var length)) { value = null; return; } value = new List(length); var span = CollectionsMarshalEx.CreateSpan(value, length); var formatter = GetFormatter(); for (int i = 0; i < length; i++) { formatter.Deserialize(ref this, ref span[i]); } } internal static class CollectionsMarshalEx { public static Span CreateSpan( List list, int length) { list.EnsureCapacity(length); ref var view = ref Unsafe.As, ListView>(ref list); view._size = length; return view._items.AsSpan(0, length); } } internal sealed class ListView { public T[] _items; public int _size; public int _version; }

Slide 33

Slide 33 text

Conclusion

Slide 34

Slide 34 text

究極のシリアライザーを作る MemoryPack https://github.com/Cysharp/MemoryPack/

Slide 35

Slide 35 text

No content