SlideShare a Scribd company logo
A (brief) overview of Span<T>
(and ReadOnlySpan<T> and Memory<T> and ReadOnlyMemory<T>)
DAVID WENGIER
@davidwengier
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”
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”
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”
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”
What is Span<T>?
• Think of it like having an array to access raw memory
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
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
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
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
* 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
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
Framework Support
https://github.com/dotnet/corefx/blob/master/src/Common/src/CoreLib/System/Int32.cs
Framework Support
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');
}
});
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
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;
}
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;
}
Limitations
• Can only live on the stack
• Implemented as a ref struct
• Can only be contained by ref structs
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
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;
}
}
Memory<T>
• “Normal” struct
• Not as performant as Span
• Can be used in more places than Span (ie, doesn’t have the
limitations)
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;
}
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
TechEmpower Plaintext
Round 14
Round 15
DAVID WENGIER
@davidwengier
Thank you!
Questions?

More Related Content

PDF
Adam Sitnik "State of the .NET Performance"
PPTX
ORAM: A Brief Overview
PDF
Acm aleppo cpc training second session
PDF
Acm aleppo cpc training ninth session
PDF
【論文紹介】Relay: A New IR for Machine Learning Frameworks
PDF
Q4.11: Using GCC Auto-Vectorizer
PDF
Engineering fast indexes
Adam Sitnik "State of the .NET Performance"
ORAM: A Brief Overview
Acm aleppo cpc training second session
Acm aleppo cpc training ninth session
【論文紹介】Relay: A New IR for Machine Learning Frameworks
Q4.11: Using GCC Auto-Vectorizer
Engineering fast indexes

What's hot (20)

PPT
Data type
PDF
PDF
Engineering fast indexes (Deepdive)
PPTX
AA-sort with SSE4.1
PPTX
16 strings-and-text-processing-120712074956-phpapp02
PPTX
Patterns of 64-bit errors in games
PDF
Vc4c development of opencl compiler for videocore4
PDF
Sparse Data Structures for Weighted Bipartite Matching
PDF
presentation
PPT
Strings Functions in C Programming
PDF
A nice 64-bit error in C
PPSX
Strings
PPTX
C++ Code as Seen by a Hypercritical Reviewer
PPTX
String in c programming
PDF
String.ppt
PPT
Strings in c
PDF
Efficient Two-level Homomorphic Encryption in Prime-order Bilinear Groups and...
PPTX
Arrays in C++ in Tamil - TNSCERT SYLLABUS PPT
PDF
Arrays and strings in c++
DOC
String in c
Data type
Engineering fast indexes (Deepdive)
AA-sort with SSE4.1
16 strings-and-text-processing-120712074956-phpapp02
Patterns of 64-bit errors in games
Vc4c development of opencl compiler for videocore4
Sparse Data Structures for Weighted Bipartite Matching
presentation
Strings Functions in C Programming
A nice 64-bit error in C
Strings
C++ Code as Seen by a Hypercritical Reviewer
String in c programming
String.ppt
Strings in c
Efficient Two-level Homomorphic Encryption in Prime-order Bilinear Groups and...
Arrays in C++ in Tamil - TNSCERT SYLLABUS PPT
Arrays and strings in c++
String in c
Ad

Similar to A (brief) overview of Span<T> (20)

PDF
State of the .Net Performance
PPTX
Tamir Dresher - DotNet 7 What's new.pptx
PDF
C# 7.x What's new and what's coming with C# 8
PPTX
Getting started cpp full
PPTX
Egor Bogatov - .NET Core intrinsics and other micro-optimizations
PDF
Modern C++
PPTX
3 (3)Arrays and Strings for 11,12,college.pptx
PPT
8871077.ppt
PDF
C# - What's next
PPTX
PPTX
C++ process new
PDF
Tools and Techniques for Understanding Threading Behavior in Android
PDF
The Ring programming language version 1.9 book - Part 100 of 210
PPTX
PPT on Python - illustrating Python for BBA, B.Tech
PPTX
Deep dumpster diving 2010
PPT
Georgy Nosenko - An introduction to the use SMT solvers for software security
PPTX
C Programming Training in Ambala ! Batra Computer Centre
PDF
ExperiencesSharingOnEmbeddedSystemDevelopment_20160321
PDF
OpenStack Congress and Datalog (English)
PPTX
Where the wild things are - Benchmarking and Micro-Optimisations
State of the .Net Performance
Tamir Dresher - DotNet 7 What's new.pptx
C# 7.x What's new and what's coming with C# 8
Getting started cpp full
Egor Bogatov - .NET Core intrinsics and other micro-optimizations
Modern C++
3 (3)Arrays and Strings for 11,12,college.pptx
8871077.ppt
C# - What's next
C++ process new
Tools and Techniques for Understanding Threading Behavior in Android
The Ring programming language version 1.9 book - Part 100 of 210
PPT on Python - illustrating Python for BBA, B.Tech
Deep dumpster diving 2010
Georgy Nosenko - An introduction to the use SMT solvers for software security
C Programming Training in Ambala ! Batra Computer Centre
ExperiencesSharingOnEmbeddedSystemDevelopment_20160321
OpenStack Congress and Datalog (English)
Where the wild things are - Benchmarking and Micro-Optimisations
Ad

More from David Wengier (6)

PPTX
A (very) opinionated guide to MSBuild and Project Files
PPTX
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
PPTX
Pragmatic Performance from NDC Oslo 2019
PPTX
Pragmatic Performance from NDC London 2019
PPTX
Introduction to Amazon Echo Skills
PPTX
Performance and Benchmarking
A (very) opinionated guide to MSBuild and Project Files
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Pragmatic Performance from NDC Oslo 2019
Pragmatic Performance from NDC London 2019
Introduction to Amazon Echo Skills
Performance and Benchmarking

Recently uploaded (20)

PPTX
Cloud computing and distributed systems.
PDF
Unlocking AI with Model Context Protocol (MCP)
PPTX
Big Data Technologies - Introduction.pptx
PDF
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Machine learning based COVID-19 study performance prediction
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Approach and Philosophy of On baking technology
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PPT
Teaching material agriculture food technology
PDF
Modernizing your data center with Dell and AMD
PDF
Review of recent advances in non-invasive hemoglobin estimation
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
Cloud computing and distributed systems.
Unlocking AI with Model Context Protocol (MCP)
Big Data Technologies - Introduction.pptx
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
Digital-Transformation-Roadmap-for-Companies.pptx
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Machine learning based COVID-19 study performance prediction
Advanced methodologies resolving dimensionality complications for autism neur...
Approach and Philosophy of On baking technology
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Teaching material agriculture food technology
Modernizing your data center with Dell and AMD
Review of recent advances in non-invasive hemoglobin estimation
20250228 LYD VKU AI Blended-Learning.pptx
“AI and Expert System Decision Support & Business Intelligence Systems”
The AUB Centre for AI in Media Proposal.docx
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Building Integrated photovoltaic BIPV_UPV.pdf
Dropbox Q2 2025 Financial Results & Investor Presentation

A (brief) overview of Span<T>

  • 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”
  • 6. What is Span<T>? • Think of it like having an array to access raw memory
  • 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. 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. 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. 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. * 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. 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
  • 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
  • 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. Memory<T> • “Normal” struct • Not as performant as Span • Can be used in more places than Span (ie, doesn’t have the limitations)
  • 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. 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