1. A (brief) overview of Span<T>
(and ReadOnlySpan<T> and Memory<T> and ReadOnlyMemory<T>)
DAVID WENGIER
@davidwengier
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. 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. 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. 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”
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. 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. 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. 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. Limitations
• Can only live on the stack
• Implemented as a ref struct
• Can only be contained by ref structs
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
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