Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

A (brief) overview of Span<T>

53 views

Published on

“System.Span<T> is a new value type at the heart of .NET [that] enables the representation of contiguous regions of arbitrary memory”.

Published in: Technology
  • Be the first to comment

A (brief) overview of Span<T>

  1. 1. A (brief) overview of Span<T> (and ReadOnlySpan<T> and Memory<T> and ReadOnlyMemory<T>) DAVID WENGIER @davidwengier
  2. 2. What is Span<T>? - Stephen Toub, MSDN Magazine, January 2018 https://msdn.microsoft.com/en-us/magazine/mt814808 “System.Span<T> is a new value type at the heart of .NET [that] enables the representation of contiguous regions of arbitrary memory”
  3. 3. What is Span<T>? • struct • Part of System.Memory, available on Nuget • Currently at rc1 version (prerelease) • .NET Standard 1.0 so can be used in .NET 4.5+ • C# 7.2-ish “System.Span<T> is a new value type at the heart of .NET [that] enables the representation of contiguous regions of arbitrary memory”
  4. 4. What is Span<T>? • High performance, low (no) overhead • Framework, CLR, JIT and GC support • Provides memory and type safety • Avoids the need for unsafe code “System.Span<T> is a new value type at the heart of .NET [that] enables the representation of contiguous regions of arbitrary memory”
  5. 5. What is Span<T>? • Native/unmanaged memory (P/Invoke) • Managed memory (.NET types) • Stack memory (stackalloc) “System.Span<T> is a new value type at the heart of .NET [that] enables the representation of contiguous regions of arbitrary memory”
  6. 6. What is Span<T>? • Think of it like having an array to access raw memory
  7. 7. var arr = new byte[10]; Span<byte> bytes = arr; bytes[0] = 42; Assert.True(arr[0] == 42); Span<byte> slice = bytes.Slice(4, 3); slice[0] = 43; Assert.True(bytes[4] == 43); Assert.True(arr[4] == 43); slice[5] = 44; // IndexOutOfRangeException
  8. 8. HeapStack 0x01 0x02 0x03 0x04 0x05 0x06 string plate = “YGG871”; plate = plate.Substring(3); int num = int.Parse(plate); plate 0x01 “YGG871” plate 0x02 “871” num 871
  9. 9. HeapStack 0x01 0x02 0x03 0x04 0x05 0x06 string plate = “YGG871”; ReadOnlySpan<char> s = plate.AsSpan(); s = s.Slice(3); int num = int.Parse(s); plate 0x01 “YGG871” 0x01 0 6 3 num 871 span offset pointer length .NET Framework 4.5+ - slow span
  10. 10. HeapStack 0x01 0x02 0x03 0x04 0x05 0x06 string plate = “YGG871”; ReadOnlySpan<char> s = plate.AsSpan(); s = s.Slice(3); int num = int.Parse(s); plate 0x01 “YGG871” 0x01+3 3 num 871 ref span length pointer .NET Core 2.0+ – fast span
  11. 11. * From Adam Sitnik - http://adamsitnik.com/Span/ Method Job Mean StdDev SpanIndexer_G et .NET 4.6 0.6054 ns 0.0007 ns SpanIndexer_G et .NET Core 1.1 0.6047 ns 0.0008 ns SpanIndexer_G et .NET Core 2.0 0.5333 ns 0.0006 ns SpanIndexer_S et .NET 4.6 0.6059 ns 0.0007 ns SpanIndexer_S et .NET Core 1.1 0.6042 ns 0.0002 ns SpanIndexer_S et .NET Core 2.0 0.5205 ns 0.0003 n
  12. 12. Method String Length Mean StdDev Scaled Gen 0 Allocated * Substring 10 8.277 ns 0.1938 ns 4.54 0.0191 40 B Slice 10 1.822 ns 0.0383 ns 1.00 - 0 B Substring 1000 85.518 ns 1.3474 ns 47.22 0.4919 1032 B Slice 1000 1.811 ns 0.0205 ns 1.00 - 0 B * Not including original string
  13. 13. Framework Support https://github.com/dotnet/corefx/blob/master/src/Common/src/CoreLib/System/Int32.cs
  14. 14. Framework Support
  15. 15. Framework Support // RandomStringLoop var stringChars = new char[Length]; for (int i = 0; i < stringChars.Length; i++) { stringChars[i] = (char)(random.Next(0, 10) + '0'); } return new string(stringChars); // RandomStringEnumerable return new string(Enumerable.Repeat("", Length) .Select(s => (char)(random.Next(0, 10) + '0')).ToArray()); // RandomStringSpan return string.Create(Length, random, (Span<char> chars, Random r) => { for (int i = 0; i < chars.Length; i++) { chars[i] = (char)(r.Next(0, 10) + '0'); } });
  16. 16. Method Length Mean Scaled Allocated RandomStringSpan 10 150.29 ns 1.00 48 B RandomStringLoop 10 156.16 ns 1.04 96 B RandomStringEnumerable 10 340.26 ns 2.27 192 B RandomStringSpan 100 1,314.91 ns 1.00 232 B RandomStringLoop 100 1,361.57 ns 1.04 456 B RandomStringEnumerable 100 2,140.91 ns 1.63 552 B RandomStringSpan 1000 12,461.32 ns 1.00 2032 B RandomStringLoop 1000 14,073.65 ns 1.13 4056 B RandomStringEnumerable 1000 20,354.63 ns 1.63 4152 B
  17. 17. When do mere mortals use it? public static bool ContainsCapitalLetters(string s) { for (int i = 0; i < s.Length; i++) { if (char.IsUpper(s[i])) { return true; } } return false; } public static int Sum(int[] a) { int sum = 0; for (int i = 0; i < a.Length; i++) { sum += a[i]; } return sum; }
  18. 18. When do mere mortals use it? public static bool ContainsCapitalLetters(ReadOnlySpan<char> s) { for (int i = 0; i < s.Length; i++) { if (char.IsUpper(s[i])) { return true; } } return false; } public static int Sum(ReadOnlySpan<int> a) { int sum = 0; for (int i = 0; i < a.Length; i++) { sum += a[i]; } return sum; }
  19. 19. Limitations • Can only live on the stack • Implemented as a ref struct • Can only be contained by ref structs
  20. 20. ref structs Structs that can exist only on the stack. New in C# 7.2 • Can’t implement interfaces • Can’t be used as generic type arguments • Can’t be boxed to object • Can’t be passed in to - or used in places inside - of async methods, iterators, nested functions or query expressions
  21. 21. async Task DoSomethingAsync(Span<byte> buffer) { buffer[0] = 0; await Something(); buffer[0] = 1; } async Task DoSomethingAsync(Span<byte> buffer) { SomethingClass cl = new SomethingClass() cl.buffer = buffer; cl.StartSomething(); } private class SomethingClass { public Span<byte> buffer; // illegal public void Start_Something() { buffer[0] = 0; DoMagicAsyncStuff().ContinueWith(End_Something); } public void End_Something() { buffer[0] = 1; } }
  22. 22. Memory<T> • “Normal” struct • Not as performant as Span • Can be used in more places than Span (ie, doesn’t have the limitations)
  23. 23. Memory<T> async Task DoSomethingAsync(Span<byte> buffer) { buffer[0] = 0; await Something(); // Bang! buffer[0] = 1; } async Task DoSomethingAsync(Memory<byte> buffer) { buffer.Span[0] = 0; await Something(); // Totally fine buffer.Span[0] = 1; }
  24. 24. Memory<T> public struct Memory<T> { private int _offset; private int _length; private int _pointer; private byte[] _data; // really OwnedMemory<T> public Span<T> Span => new Span<T>(_data, _pointer, _offset, _length); } * Not real
  25. 25. TechEmpower Plaintext Round 14 Round 15
  26. 26. DAVID WENGIER @davidwengier Thank you! Questions?

×