SlideShare a Scribd company logo
Performance in
.NET Core
Gdańsk, 2019.11.21
2
Number of requests on production
Numberofrequests
3
Measurement tools
JetBrains dotTrace
JetBrains dotMemory
4
Size of objects
Namespace Allocated bytes
Allocated
objects
Collected bytes
Collected
objects
Newtonsoft
JSON
162 368 6 803 105 168 5 851
JSON.NET 68 276 2 122 39 564 1 750
5
The most allocated types
2.2
3.0
6
Allocated strings by Newtonsoft
7
Time of processing requests (smaller is better)
436
684
775 792
172
1768
282
353
581
677 720
160
1463
207
0
200
400
600
800
1000
1200
1400
1600
1800
2000
Time[ms]
ASP.NET Core 2.2 ASP .NET Core 3.0
8
What’s the gain?
ASP.NET Core 2.2
4 909 ms
ASP.NET Core 3.0
4 161 ms
748 ms
-
=
Pipes
10
Hypothetical Use Case
Company needs to report all sale
transactions quaterly for statistics purposes.
11
Hypothetical Use Case
Company needs to report all sale
transactions quaterly for statistics purposes.
Since the Company makes thousands of
transactions every day - report file is very
large.
12
Hypothetical Use Case
Company needs to report all sale
transactions quaterly for statistics purposes.
Since the Company makes thousands of
transactions every day - report file is very
large.
Let’s assume the report is a CSV file.
13
Hypothetical Use Case
Company needs to report all sale
transactions quaterly for statistics purposes.
Since the Company makes thousands of
transactions every day - report file is very
large.
Let’s assume the report is a CSV file.
14
Naïve approach 1
app.Run(context => ProcessRequestAsync(context.Request.Body));
// NAIVE APPROACH
private async Task ProcessRequestAsync(Stream stream)
{
var buffer = new byte[1024];
while(true)
{
var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
return; // EOF
}
ProcessRowData(buffer, bytesRead);
}
}
15
Naïve approach 2
// BETTER APPROACH
private async Task ProcessRequestAsync(Stream stream)
{
var buffer = new byte[1024];
while (true)
{
var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
return; // EOF
}
var newLinePos = -1;
var bytesChecked = 0;
do
{
newLinePos = Array.IndexOf(buffer, (byte)'n', bytesChecked, bytesRead - bytesChecked);
if (newLinePos >= 0)
{
var lineLength = newLinePos - bytesChecked;
ProcessRowData(buffer, bytesChecked, lineLength);
}
bytesChecked += newLinePos + 1;
}
while (newLinePos > 0);
}
}
16
CSV might be tricky
Some product; 5.0; "Amazingn
Category"; 10n
Other product; 1.0; Boring category; 2n
17
CSV might be tricky
Some product; 5.0; "Amazingn
Category"; 10n
Other product; 1.0; Boring category; 2n
18
How we can improve our approach?
We can allocate bigger buffer when we face longer line or multiline record
19
How we can improve our approach?
We can allocate bigger buffer when we face longer line or multiline record
We can create own pool of buffers, new buffer would be created when the previous gets
filled up (i.e. in 80% or more).
20
System.IO.Pipelines to the rescue
The mentioned issues can easily be solved by using Pipe.
21
System.IO.Pipelines to the rescue
The mentioned issues can easily be solved by using Pipe.
Pipe​
PipeWriter PipeReader
22
Pipes
private async Task ProcessRequestAsync(Stream stream)
{
var pipe = new Pipe();
var readFileTask = ReadFileAsync(stream, pipe.Writer);
var processFileTask = ProcessFileAsync(pipe.Reader);
await Task.WhenAll(readFileTask, processFileTask);
}
23
PipeWriter
private async Task ReadFileAsync(Stream stream, PipeWriter pipeWriter)
{
while (true)
{
Memory<byte> memory = pipeWriter.GetMemory(BufferSize);
int bytesRead = await stream.ReadAsync(memory);
if (bytesRead == 0)
{
break;
}
pipeWriter.Advance(bytesRead);
// flush data to PipeReader
FlushResult flushResult = await pipeWriter.FlushAsync();
if (flushResult.IsCompleted)
{
break;
}
}
pipeWriter.Complete(); // we are done
}
24
PipeReader
private async Task ProcessFileAsync(PipeReader pipeReader)
{
while(true)
{
ReadResult result = await pipeReader.ReadAsync();
ReadOnlySequence<byte> buffer = result.Buffer;
SequencePosition? position = null;
do
{
position = buffer.PositionOf((byte)'n'); // find position of newline character, read multiline row…
if (position != null)
{
ProcessRowData(buffer.Slice(0, position.Value));
buffer = buffer.Slice(buffer.GetPosition(1, position.Value)); // move to next line
}
}
while (position != null);
if (result.IsCompleted)
{
break;
}
pipeReader.AdvanceTo(buffer.Start, buffer.End); // let know the PipeReader how much bytes were consumed
}
pipeReader.Complete(); // we are done
}
25
Partial read
Pipe.Reader.ReadAsync() Some product; 5
Some product; 5 .PositionOf((byte)'n') null
Pipe.Reader.ReadAsync() Some product; 5.0; Some Categoryn
Some product; 5.0; Some Categoryn .PositionOf((byte)'n') SequencePosition
Pipe.Reader.AdvanceTo( SequencePosition +1)
Pipe.Reader.ReadAsync() Other product; 3.0;…
26
ReadOnlySequence<T>, SequencePosition
Pipe
ReadOnlySequence
EndStart
27
Backpressure & flow control
28
Backpressure & flow control
29
Backpressure & flow control
30
Backpressure & flow control
31
Backpressure & flow control
32
Backpressure & flow control
PauseWriterThreshold
33
Backpressure & flow control
PauseWriterThreshold
34
Backpressure & flow control
PauseWriterThreshold
35
Backpressure & flow control
PauseWriterThreshold
36
Backpressure & flow control
PauseWriterThreshold
ResumeWriterThreshold
37
Backpressure & flow control
PauseWriterThreshold
ResumeWriterThreshold
38
How is it relevant?
39
How is it relevant?
Pipes originally were introduced for internal use in Kestrel. Eventually, the’ve
evolved into a part of public API.
40
How is it relevant?
Pipes originally were introduced for internal use in Kestrel. Eventually, the’ve
evolved into a part of public API.
The body of request in ASP.NET Core 3.0 is exposed via BodyReader property of
the HttpContext. BodyReader is in fact PipeReader.
41
How is it relevant?
Pipes originally were introduced for internal use in Kestrel. Eventually, the’ve
evolved into a part of public API.
The body of request in ASP.NET Core 3.0 is exposed via BodyReader property of
the HttpContext. BodyReader is in fact PipeReader.
Response body can be written with BodyWriter (PipeWriter).
Span<T>
and Memory<T>
43
Span<T>
.NET Core 2.1
ReadOnlySpan<T>
C# 7.2
ref struct
Array Slicing
44
Span<T> - Example
N A M E @ E M A I L
45
Span<T> - Example
N A M E @ E M A I L
public ReadOnlySpan<char> GetName(ReadOnlySpan<char> email)
{
var @position = email.LastIndexOf(‘@’);
return @position == -1
? ReadOnlySpan<char>.Empty
: email.Slice(0, @position);
}
46
Span<T> - Two versions
Background vector Created by brgfx - www.freepik.com
47
Span<T> - Two versions
Method Job Mean StdDev
SpanIndexer_Get .NET 4.6 0.6054 ns 0.0007 ns
SpanIndexer_Get .NET Core 1.1 0.6047 ns 0.0008 ns
SpanIndexer_Get .NET Core 2.0 0.5333 ns 0.0006 ns
SpanIndexer_Set .NET 4.6 0.6059 ns 0.0007 ns
SpanIndexer_Set .NET Core 1.1 0.6042 ns 0.0002 ns
SpanIndexer_Set .NET Core 2.0 0.5205 ns 0.0003 ns
Source: Adam Sitnik - https://adamsitnik.com/Span/#using-span
48
Limitations of Span<T>
Heap
as generic type
argument
implement any
interfaces
No
parameter of async
method
49
Memory<T>
.NET Core 2.1
Asynchronous world
C# 7.2
ReadOnlyMemory<T>
On Heap
Wrapper of Span<T>
50
Span<T> and Memory<T> - Supported in
.NET Standard 1.0 1.1 1.2
.NET Core 1.0 1.0 1.0
.NET Framework 1 4.5 4.5 4.5.1
Mono 4.6 4.6 4.6
Xamarin.iOS 10.0 10.0 10.0
Xamarin.Mac 3.0 3.0 3.0
Xamarin.Android 7.0 7.0 7.0
Universal Windows
Platform
10.0 10.0 10.0
Unity 2018.1 2018.1 2018.1
Json.NET
52
Json.NET – High performance JSON serializer and deserializer
.NET Standard 1.6 2.0 2.1
.NET Core 1.0 2.0 3.0
.NET Framework 4.6.1 4.6.1 Won’t support
Mono 4.6 5.4 6.4
Xamarin.iOS 10.0 10.14 12.16
Xamarin.Mac 3.0 3.8 5.16
Xamarin.Android 7.0 8.0 10.0
Universal Windows
Platform
10.0.16299 10.0. 16299 TBD
Unity 2018.1 2018.1 TBD
await FlushAsync();
Questions();

More Related Content

What's hot

Data Structures and Performance for Scientific Computing with Hadoop and Dumb...
Data Structures and Performance for Scientific Computing with Hadoop and Dumb...Data Structures and Performance for Scientific Computing with Hadoop and Dumb...
Data Structures and Performance for Scientific Computing with Hadoop and Dumb...
Austin Benson
 
Accelerate Reed-Solomon coding for Fault-Tolerance in RAID-like system
Accelerate Reed-Solomon coding for Fault-Tolerance in RAID-like systemAccelerate Reed-Solomon coding for Fault-Tolerance in RAID-like system
Accelerate Reed-Solomon coding for Fault-Tolerance in RAID-like system
Shuai Yuan
 
Building a High-Performance Distributed Task Queue on MongoDB
Building a High-Performance Distributed Task Queue on MongoDBBuilding a High-Performance Distributed Task Queue on MongoDB
Building a High-Performance Distributed Task Queue on MongoDB
MongoDB
 
Cypher for Gremlin
Cypher for GremlinCypher for Gremlin
Cypher for Gremlin
openCypher
 
Why learn Internals?
Why learn Internals?Why learn Internals?
Why learn Internals?
Shaul Rosenzwieg
 
Bigdata Presentation
Bigdata PresentationBigdata Presentation
Bigdata Presentation
Yonas Gidey
 
Building Scalable, Distributed Job Queues with Redis and Redis::Client
Building Scalable, Distributed Job Queues with Redis and Redis::ClientBuilding Scalable, Distributed Job Queues with Redis and Redis::Client
Building Scalable, Distributed Job Queues with Redis and Redis::Client
Mike Friedman
 
Optimizing with persistent data structures (LLVM Cauldron 2016)
Optimizing with persistent data structures (LLVM Cauldron 2016)Optimizing with persistent data structures (LLVM Cauldron 2016)
Optimizing with persistent data structures (LLVM Cauldron 2016)
Igalia
 
Data correlation using PySpark and HDFS
Data correlation using PySpark and HDFSData correlation using PySpark and HDFS
Data correlation using PySpark and HDFS
John Conley
 
NoSQL and SQL Anti Patterns
NoSQL and SQL Anti PatternsNoSQL and SQL Anti Patterns
NoSQL and SQL Anti Patterns
Gleicon Moraes
 
InfluxDB IOx Tech Talks: The Impossible Dream: Easy-to-Use, Super Fast Softw...
InfluxDB IOx Tech Talks: The Impossible Dream:  Easy-to-Use, Super Fast Softw...InfluxDB IOx Tech Talks: The Impossible Dream:  Easy-to-Use, Super Fast Softw...
InfluxDB IOx Tech Talks: The Impossible Dream: Easy-to-Use, Super Fast Softw...
InfluxData
 
Better Full Text Search in PostgreSQL
Better Full Text Search in PostgreSQLBetter Full Text Search in PostgreSQL
Better Full Text Search in PostgreSQL
Artur Zakirov
 
DaWaK'07
DaWaK'07DaWaK'07
DaWaK'07
Ronnie Alves
 
The Ring programming language version 1.9 book - Part 17 of 210
The Ring programming language version 1.9 book - Part 17 of 210The Ring programming language version 1.9 book - Part 17 of 210
The Ring programming language version 1.9 book - Part 17 of 210
Mahmoud Samir Fayed
 
Web program-peformance-optimization
Web program-peformance-optimizationWeb program-peformance-optimization
Web program-peformance-optimization
xiaojueqq12345
 
Fun421 stephens
Fun421 stephensFun421 stephens
Fun421 stephens
Tess Ferrandez
 
Fast Insight from Fast Data: Integrating ClickHouse and Apache Kafka
Fast Insight from Fast Data: Integrating ClickHouse and Apache KafkaFast Insight from Fast Data: Integrating ClickHouse and Apache Kafka
Fast Insight from Fast Data: Integrating ClickHouse and Apache Kafka
Altinity Ltd
 
Wayfair Use Case: The four R's of Metrics Delivery
Wayfair Use Case: The four R's of Metrics DeliveryWayfair Use Case: The four R's of Metrics Delivery
Wayfair Use Case: The four R's of Metrics Delivery
InfluxData
 
Supporting HDF5 in GrADS
Supporting HDF5 in GrADSSupporting HDF5 in GrADS
Sessionization with Spark streaming
Sessionization with Spark streamingSessionization with Spark streaming
Sessionization with Spark streaming
Ramūnas Urbonas
 

What's hot (20)

Data Structures and Performance for Scientific Computing with Hadoop and Dumb...
Data Structures and Performance for Scientific Computing with Hadoop and Dumb...Data Structures and Performance for Scientific Computing with Hadoop and Dumb...
Data Structures and Performance for Scientific Computing with Hadoop and Dumb...
 
Accelerate Reed-Solomon coding for Fault-Tolerance in RAID-like system
Accelerate Reed-Solomon coding for Fault-Tolerance in RAID-like systemAccelerate Reed-Solomon coding for Fault-Tolerance in RAID-like system
Accelerate Reed-Solomon coding for Fault-Tolerance in RAID-like system
 
Building a High-Performance Distributed Task Queue on MongoDB
Building a High-Performance Distributed Task Queue on MongoDBBuilding a High-Performance Distributed Task Queue on MongoDB
Building a High-Performance Distributed Task Queue on MongoDB
 
Cypher for Gremlin
Cypher for GremlinCypher for Gremlin
Cypher for Gremlin
 
Why learn Internals?
Why learn Internals?Why learn Internals?
Why learn Internals?
 
Bigdata Presentation
Bigdata PresentationBigdata Presentation
Bigdata Presentation
 
Building Scalable, Distributed Job Queues with Redis and Redis::Client
Building Scalable, Distributed Job Queues with Redis and Redis::ClientBuilding Scalable, Distributed Job Queues with Redis and Redis::Client
Building Scalable, Distributed Job Queues with Redis and Redis::Client
 
Optimizing with persistent data structures (LLVM Cauldron 2016)
Optimizing with persistent data structures (LLVM Cauldron 2016)Optimizing with persistent data structures (LLVM Cauldron 2016)
Optimizing with persistent data structures (LLVM Cauldron 2016)
 
Data correlation using PySpark and HDFS
Data correlation using PySpark and HDFSData correlation using PySpark and HDFS
Data correlation using PySpark and HDFS
 
NoSQL and SQL Anti Patterns
NoSQL and SQL Anti PatternsNoSQL and SQL Anti Patterns
NoSQL and SQL Anti Patterns
 
InfluxDB IOx Tech Talks: The Impossible Dream: Easy-to-Use, Super Fast Softw...
InfluxDB IOx Tech Talks: The Impossible Dream:  Easy-to-Use, Super Fast Softw...InfluxDB IOx Tech Talks: The Impossible Dream:  Easy-to-Use, Super Fast Softw...
InfluxDB IOx Tech Talks: The Impossible Dream: Easy-to-Use, Super Fast Softw...
 
Better Full Text Search in PostgreSQL
Better Full Text Search in PostgreSQLBetter Full Text Search in PostgreSQL
Better Full Text Search in PostgreSQL
 
DaWaK'07
DaWaK'07DaWaK'07
DaWaK'07
 
The Ring programming language version 1.9 book - Part 17 of 210
The Ring programming language version 1.9 book - Part 17 of 210The Ring programming language version 1.9 book - Part 17 of 210
The Ring programming language version 1.9 book - Part 17 of 210
 
Web program-peformance-optimization
Web program-peformance-optimizationWeb program-peformance-optimization
Web program-peformance-optimization
 
Fun421 stephens
Fun421 stephensFun421 stephens
Fun421 stephens
 
Fast Insight from Fast Data: Integrating ClickHouse and Apache Kafka
Fast Insight from Fast Data: Integrating ClickHouse and Apache KafkaFast Insight from Fast Data: Integrating ClickHouse and Apache Kafka
Fast Insight from Fast Data: Integrating ClickHouse and Apache Kafka
 
Wayfair Use Case: The four R's of Metrics Delivery
Wayfair Use Case: The four R's of Metrics DeliveryWayfair Use Case: The four R's of Metrics Delivery
Wayfair Use Case: The four R's of Metrics Delivery
 
Supporting HDF5 in GrADS
Supporting HDF5 in GrADSSupporting HDF5 in GrADS
Supporting HDF5 in GrADS
 
Sessionization with Spark streaming
Sessionization with Spark streamingSessionization with Spark streaming
Sessionization with Spark streaming
 

Similar to Performance .NET Core - M. Terech, P. Janowski

Workshop "Can my .NET application use less CPU / RAM?", Yevhen Tatarynov
Workshop "Can my .NET application use less CPU / RAM?", Yevhen TatarynovWorkshop "Can my .NET application use less CPU / RAM?", Yevhen Tatarynov
Workshop "Can my .NET application use less CPU / RAM?", Yevhen Tatarynov
Fwdays
 
Exploitation Crash Course
Exploitation Crash CourseExploitation Crash Course
Exploitation Crash Course
UTD Computer Security Group
 
[ACNA2022] Hadoop Vectored IO_ your data just got faster!.pdf
[ACNA2022] Hadoop Vectored IO_ your data just got faster!.pdf[ACNA2022] Hadoop Vectored IO_ your data just got faster!.pdf
[ACNA2022] Hadoop Vectored IO_ your data just got faster!.pdf
MukundThakur22
 
Runtime Bytecode Transformation for Smalltalk
Runtime Bytecode Transformation for SmalltalkRuntime Bytecode Transformation for Smalltalk
Runtime Bytecode Transformation for Smalltalk
ESUG
 
H2O World - What's New in H2O with Cliff Click
H2O World - What's New in H2O with Cliff ClickH2O World - What's New in H2O with Cliff Click
H2O World - What's New in H2O with Cliff Click
Sri Ambati
 
Lp seminar
Lp seminarLp seminar
Lp seminar
guestdff961
 
あなたのScalaを爆速にする7つの方法
あなたのScalaを爆速にする7つの方法あなたのScalaを爆速にする7つの方法
あなたのScalaを爆速にする7つの方法
x1 ichi
 
A New Chapter of Data Processing with CDK
A New Chapter of Data Processing with CDKA New Chapter of Data Processing with CDK
A New Chapter of Data Processing with CDK
Shu-Jeng Hsieh
 
Heading for a Record: Chromium, the 5th Check
Heading for a Record: Chromium, the 5th CheckHeading for a Record: Chromium, the 5th Check
Heading for a Record: Chromium, the 5th Check
PVS-Studio
 
Perly Parallel Processing of Fixed Width Data Records
Perly Parallel Processing of Fixed Width Data RecordsPerly Parallel Processing of Fixed Width Data Records
Perly Parallel Processing of Fixed Width Data Records
Workhorse Computing
 
XDP in Practice: DDoS Mitigation @Cloudflare
XDP in Practice: DDoS Mitigation @CloudflareXDP in Practice: DDoS Mitigation @Cloudflare
XDP in Practice: DDoS Mitigation @Cloudflare
C4Media
 
Data Pipeline at Tapad
Data Pipeline at TapadData Pipeline at Tapad
Data Pipeline at Tapad
Toby Matejovsky
 
Quantifying Container Runtime Performance: OSCON 2017 Open Container Day
Quantifying Container Runtime Performance: OSCON 2017 Open Container DayQuantifying Container Runtime Performance: OSCON 2017 Open Container Day
Quantifying Container Runtime Performance: OSCON 2017 Open Container Day
Phil Estes
 
Mass Report Generation Using REST APIs
Mass Report Generation Using REST APIsMass Report Generation Using REST APIs
Mass Report Generation Using REST APIs
Salesforce Developers
 
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
Ontico
 
The CppCat Analyzer Checks TortoiseGit
The CppCat Analyzer Checks TortoiseGitThe CppCat Analyzer Checks TortoiseGit
The CppCat Analyzer Checks TortoiseGit
Andrey Karpov
 
Node.js - Advanced Basics
Node.js - Advanced BasicsNode.js - Advanced Basics
Node.js - Advanced Basics
Doug Jones
 
JDK1.7 features
JDK1.7 featuresJDK1.7 features
JDK1.7 features
india_mani
 
Apache Big Data EU 2015 - Phoenix
Apache Big Data EU 2015 - PhoenixApache Big Data EU 2015 - Phoenix
Apache Big Data EU 2015 - Phoenix
Nick Dimiduk
 
Linux Kernel, tested by the Linux-version of PVS-Studio
Linux Kernel, tested by the Linux-version of PVS-StudioLinux Kernel, tested by the Linux-version of PVS-Studio
Linux Kernel, tested by the Linux-version of PVS-Studio
PVS-Studio
 

Similar to Performance .NET Core - M. Terech, P. Janowski (20)

Workshop "Can my .NET application use less CPU / RAM?", Yevhen Tatarynov
Workshop "Can my .NET application use less CPU / RAM?", Yevhen TatarynovWorkshop "Can my .NET application use less CPU / RAM?", Yevhen Tatarynov
Workshop "Can my .NET application use less CPU / RAM?", Yevhen Tatarynov
 
Exploitation Crash Course
Exploitation Crash CourseExploitation Crash Course
Exploitation Crash Course
 
[ACNA2022] Hadoop Vectored IO_ your data just got faster!.pdf
[ACNA2022] Hadoop Vectored IO_ your data just got faster!.pdf[ACNA2022] Hadoop Vectored IO_ your data just got faster!.pdf
[ACNA2022] Hadoop Vectored IO_ your data just got faster!.pdf
 
Runtime Bytecode Transformation for Smalltalk
Runtime Bytecode Transformation for SmalltalkRuntime Bytecode Transformation for Smalltalk
Runtime Bytecode Transformation for Smalltalk
 
H2O World - What's New in H2O with Cliff Click
H2O World - What's New in H2O with Cliff ClickH2O World - What's New in H2O with Cliff Click
H2O World - What's New in H2O with Cliff Click
 
Lp seminar
Lp seminarLp seminar
Lp seminar
 
あなたのScalaを爆速にする7つの方法
あなたのScalaを爆速にする7つの方法あなたのScalaを爆速にする7つの方法
あなたのScalaを爆速にする7つの方法
 
A New Chapter of Data Processing with CDK
A New Chapter of Data Processing with CDKA New Chapter of Data Processing with CDK
A New Chapter of Data Processing with CDK
 
Heading for a Record: Chromium, the 5th Check
Heading for a Record: Chromium, the 5th CheckHeading for a Record: Chromium, the 5th Check
Heading for a Record: Chromium, the 5th Check
 
Perly Parallel Processing of Fixed Width Data Records
Perly Parallel Processing of Fixed Width Data RecordsPerly Parallel Processing of Fixed Width Data Records
Perly Parallel Processing of Fixed Width Data Records
 
XDP in Practice: DDoS Mitigation @Cloudflare
XDP in Practice: DDoS Mitigation @CloudflareXDP in Practice: DDoS Mitigation @Cloudflare
XDP in Practice: DDoS Mitigation @Cloudflare
 
Data Pipeline at Tapad
Data Pipeline at TapadData Pipeline at Tapad
Data Pipeline at Tapad
 
Quantifying Container Runtime Performance: OSCON 2017 Open Container Day
Quantifying Container Runtime Performance: OSCON 2017 Open Container DayQuantifying Container Runtime Performance: OSCON 2017 Open Container Day
Quantifying Container Runtime Performance: OSCON 2017 Open Container Day
 
Mass Report Generation Using REST APIs
Mass Report Generation Using REST APIsMass Report Generation Using REST APIs
Mass Report Generation Using REST APIs
 
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
Полнотекстовый поиск в PostgreSQL за миллисекунды (Олег Бартунов, Александр К...
 
The CppCat Analyzer Checks TortoiseGit
The CppCat Analyzer Checks TortoiseGitThe CppCat Analyzer Checks TortoiseGit
The CppCat Analyzer Checks TortoiseGit
 
Node.js - Advanced Basics
Node.js - Advanced BasicsNode.js - Advanced Basics
Node.js - Advanced Basics
 
JDK1.7 features
JDK1.7 featuresJDK1.7 features
JDK1.7 features
 
Apache Big Data EU 2015 - Phoenix
Apache Big Data EU 2015 - PhoenixApache Big Data EU 2015 - Phoenix
Apache Big Data EU 2015 - Phoenix
 
Linux Kernel, tested by the Linux-version of PVS-Studio
Linux Kernel, tested by the Linux-version of PVS-StudioLinux Kernel, tested by the Linux-version of PVS-Studio
Linux Kernel, tested by the Linux-version of PVS-Studio
 

Recently uploaded

Dandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity serverDandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity server
Antonios Katsarakis
 
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge GraphGraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
Neo4j
 
Introduction of Cybersecurity with OSS at Code Europe 2024
Introduction of Cybersecurity with OSS  at Code Europe 2024Introduction of Cybersecurity with OSS  at Code Europe 2024
Introduction of Cybersecurity with OSS at Code Europe 2024
Hiroshi SHIBATA
 
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
saastr
 
What is an RPA CoE? Session 1 – CoE Vision
What is an RPA CoE?  Session 1 – CoE VisionWhat is an RPA CoE?  Session 1 – CoE Vision
What is an RPA CoE? Session 1 – CoE Vision
DianaGray10
 
Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)
Jakub Marek
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
Tatiana Kojar
 
Y-Combinator seed pitch deck template PP
Y-Combinator seed pitch deck template PPY-Combinator seed pitch deck template PP
Y-Combinator seed pitch deck template PP
c5vrf27qcz
 
Principle of conventional tomography-Bibash Shahi ppt..pptx
Principle of conventional tomography-Bibash Shahi ppt..pptxPrinciple of conventional tomography-Bibash Shahi ppt..pptx
Principle of conventional tomography-Bibash Shahi ppt..pptx
BibashShahi
 
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success StoryDriving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Safe Software
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
Zilliz
 
The Microsoft 365 Migration Tutorial For Beginner.pptx
The Microsoft 365 Migration Tutorial For Beginner.pptxThe Microsoft 365 Migration Tutorial For Beginner.pptx
The Microsoft 365 Migration Tutorial For Beginner.pptx
operationspcvita
 
HCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAUHCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAU
panagenda
 
Harnessing the Power of NLP and Knowledge Graphs for Opioid Research
Harnessing the Power of NLP and Knowledge Graphs for Opioid ResearchHarnessing the Power of NLP and Knowledge Graphs for Opioid Research
Harnessing the Power of NLP and Knowledge Graphs for Opioid Research
Neo4j
 
Essentials of Automations: Exploring Attributes & Automation Parameters
Essentials of Automations: Exploring Attributes & Automation ParametersEssentials of Automations: Exploring Attributes & Automation Parameters
Essentials of Automations: Exploring Attributes & Automation Parameters
Safe Software
 
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
Edge AI and Vision Alliance
 
"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
Fwdays
 
Apps Break Data
Apps Break DataApps Break Data
Apps Break Data
Ivo Velitchkov
 
Digital Banking in the Cloud: How Citizens Bank Unlocked Their Mainframe
Digital Banking in the Cloud: How Citizens Bank Unlocked Their MainframeDigital Banking in the Cloud: How Citizens Bank Unlocked Their Mainframe
Digital Banking in the Cloud: How Citizens Bank Unlocked Their Mainframe
Precisely
 
Biomedical Knowledge Graphs for Data Scientists and Bioinformaticians
Biomedical Knowledge Graphs for Data Scientists and BioinformaticiansBiomedical Knowledge Graphs for Data Scientists and Bioinformaticians
Biomedical Knowledge Graphs for Data Scientists and Bioinformaticians
Neo4j
 

Recently uploaded (20)

Dandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity serverDandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity server
 
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge GraphGraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
 
Introduction of Cybersecurity with OSS at Code Europe 2024
Introduction of Cybersecurity with OSS  at Code Europe 2024Introduction of Cybersecurity with OSS  at Code Europe 2024
Introduction of Cybersecurity with OSS at Code Europe 2024
 
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
 
What is an RPA CoE? Session 1 – CoE Vision
What is an RPA CoE?  Session 1 – CoE VisionWhat is an RPA CoE?  Session 1 – CoE Vision
What is an RPA CoE? Session 1 – CoE Vision
 
Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
 
Y-Combinator seed pitch deck template PP
Y-Combinator seed pitch deck template PPY-Combinator seed pitch deck template PP
Y-Combinator seed pitch deck template PP
 
Principle of conventional tomography-Bibash Shahi ppt..pptx
Principle of conventional tomography-Bibash Shahi ppt..pptxPrinciple of conventional tomography-Bibash Shahi ppt..pptx
Principle of conventional tomography-Bibash Shahi ppt..pptx
 
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success StoryDriving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success Story
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
 
The Microsoft 365 Migration Tutorial For Beginner.pptx
The Microsoft 365 Migration Tutorial For Beginner.pptxThe Microsoft 365 Migration Tutorial For Beginner.pptx
The Microsoft 365 Migration Tutorial For Beginner.pptx
 
HCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAUHCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAU
 
Harnessing the Power of NLP and Knowledge Graphs for Opioid Research
Harnessing the Power of NLP and Knowledge Graphs for Opioid ResearchHarnessing the Power of NLP and Knowledge Graphs for Opioid Research
Harnessing the Power of NLP and Knowledge Graphs for Opioid Research
 
Essentials of Automations: Exploring Attributes & Automation Parameters
Essentials of Automations: Exploring Attributes & Automation ParametersEssentials of Automations: Exploring Attributes & Automation Parameters
Essentials of Automations: Exploring Attributes & Automation Parameters
 
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
 
"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
 
Apps Break Data
Apps Break DataApps Break Data
Apps Break Data
 
Digital Banking in the Cloud: How Citizens Bank Unlocked Their Mainframe
Digital Banking in the Cloud: How Citizens Bank Unlocked Their MainframeDigital Banking in the Cloud: How Citizens Bank Unlocked Their Mainframe
Digital Banking in the Cloud: How Citizens Bank Unlocked Their Mainframe
 
Biomedical Knowledge Graphs for Data Scientists and Bioinformaticians
Biomedical Knowledge Graphs for Data Scientists and BioinformaticiansBiomedical Knowledge Graphs for Data Scientists and Bioinformaticians
Biomedical Knowledge Graphs for Data Scientists and Bioinformaticians
 

Performance .NET Core - M. Terech, P. Janowski

  • 2. 2 Number of requests on production Numberofrequests
  • 4. 4 Size of objects Namespace Allocated bytes Allocated objects Collected bytes Collected objects Newtonsoft JSON 162 368 6 803 105 168 5 851 JSON.NET 68 276 2 122 39 564 1 750
  • 5. 5 The most allocated types 2.2 3.0
  • 7. 7 Time of processing requests (smaller is better) 436 684 775 792 172 1768 282 353 581 677 720 160 1463 207 0 200 400 600 800 1000 1200 1400 1600 1800 2000 Time[ms] ASP.NET Core 2.2 ASP .NET Core 3.0
  • 8. 8 What’s the gain? ASP.NET Core 2.2 4 909 ms ASP.NET Core 3.0 4 161 ms 748 ms - =
  • 10. 10 Hypothetical Use Case Company needs to report all sale transactions quaterly for statistics purposes.
  • 11. 11 Hypothetical Use Case Company needs to report all sale transactions quaterly for statistics purposes. Since the Company makes thousands of transactions every day - report file is very large.
  • 12. 12 Hypothetical Use Case Company needs to report all sale transactions quaterly for statistics purposes. Since the Company makes thousands of transactions every day - report file is very large. Let’s assume the report is a CSV file.
  • 13. 13 Hypothetical Use Case Company needs to report all sale transactions quaterly for statistics purposes. Since the Company makes thousands of transactions every day - report file is very large. Let’s assume the report is a CSV file.
  • 14. 14 Naïve approach 1 app.Run(context => ProcessRequestAsync(context.Request.Body)); // NAIVE APPROACH private async Task ProcessRequestAsync(Stream stream) { var buffer = new byte[1024]; while(true) { var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length); if (bytesRead == 0) { return; // EOF } ProcessRowData(buffer, bytesRead); } }
  • 15. 15 Naïve approach 2 // BETTER APPROACH private async Task ProcessRequestAsync(Stream stream) { var buffer = new byte[1024]; while (true) { var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length); if (bytesRead == 0) { return; // EOF } var newLinePos = -1; var bytesChecked = 0; do { newLinePos = Array.IndexOf(buffer, (byte)'n', bytesChecked, bytesRead - bytesChecked); if (newLinePos >= 0) { var lineLength = newLinePos - bytesChecked; ProcessRowData(buffer, bytesChecked, lineLength); } bytesChecked += newLinePos + 1; } while (newLinePos > 0); } }
  • 16. 16 CSV might be tricky Some product; 5.0; "Amazingn Category"; 10n Other product; 1.0; Boring category; 2n
  • 17. 17 CSV might be tricky Some product; 5.0; "Amazingn Category"; 10n Other product; 1.0; Boring category; 2n
  • 18. 18 How we can improve our approach? We can allocate bigger buffer when we face longer line or multiline record
  • 19. 19 How we can improve our approach? We can allocate bigger buffer when we face longer line or multiline record We can create own pool of buffers, new buffer would be created when the previous gets filled up (i.e. in 80% or more).
  • 20. 20 System.IO.Pipelines to the rescue The mentioned issues can easily be solved by using Pipe.
  • 21. 21 System.IO.Pipelines to the rescue The mentioned issues can easily be solved by using Pipe. Pipe​ PipeWriter PipeReader
  • 22. 22 Pipes private async Task ProcessRequestAsync(Stream stream) { var pipe = new Pipe(); var readFileTask = ReadFileAsync(stream, pipe.Writer); var processFileTask = ProcessFileAsync(pipe.Reader); await Task.WhenAll(readFileTask, processFileTask); }
  • 23. 23 PipeWriter private async Task ReadFileAsync(Stream stream, PipeWriter pipeWriter) { while (true) { Memory<byte> memory = pipeWriter.GetMemory(BufferSize); int bytesRead = await stream.ReadAsync(memory); if (bytesRead == 0) { break; } pipeWriter.Advance(bytesRead); // flush data to PipeReader FlushResult flushResult = await pipeWriter.FlushAsync(); if (flushResult.IsCompleted) { break; } } pipeWriter.Complete(); // we are done }
  • 24. 24 PipeReader private async Task ProcessFileAsync(PipeReader pipeReader) { while(true) { ReadResult result = await pipeReader.ReadAsync(); ReadOnlySequence<byte> buffer = result.Buffer; SequencePosition? position = null; do { position = buffer.PositionOf((byte)'n'); // find position of newline character, read multiline row… if (position != null) { ProcessRowData(buffer.Slice(0, position.Value)); buffer = buffer.Slice(buffer.GetPosition(1, position.Value)); // move to next line } } while (position != null); if (result.IsCompleted) { break; } pipeReader.AdvanceTo(buffer.Start, buffer.End); // let know the PipeReader how much bytes were consumed } pipeReader.Complete(); // we are done }
  • 25. 25 Partial read Pipe.Reader.ReadAsync() Some product; 5 Some product; 5 .PositionOf((byte)'n') null Pipe.Reader.ReadAsync() Some product; 5.0; Some Categoryn Some product; 5.0; Some Categoryn .PositionOf((byte)'n') SequencePosition Pipe.Reader.AdvanceTo( SequencePosition +1) Pipe.Reader.ReadAsync() Other product; 3.0;…
  • 32. 32 Backpressure & flow control PauseWriterThreshold
  • 33. 33 Backpressure & flow control PauseWriterThreshold
  • 34. 34 Backpressure & flow control PauseWriterThreshold
  • 35. 35 Backpressure & flow control PauseWriterThreshold
  • 36. 36 Backpressure & flow control PauseWriterThreshold ResumeWriterThreshold
  • 37. 37 Backpressure & flow control PauseWriterThreshold ResumeWriterThreshold
  • 38. 38 How is it relevant?
  • 39. 39 How is it relevant? Pipes originally were introduced for internal use in Kestrel. Eventually, the’ve evolved into a part of public API.
  • 40. 40 How is it relevant? Pipes originally were introduced for internal use in Kestrel. Eventually, the’ve evolved into a part of public API. The body of request in ASP.NET Core 3.0 is exposed via BodyReader property of the HttpContext. BodyReader is in fact PipeReader.
  • 41. 41 How is it relevant? Pipes originally were introduced for internal use in Kestrel. Eventually, the’ve evolved into a part of public API. The body of request in ASP.NET Core 3.0 is exposed via BodyReader property of the HttpContext. BodyReader is in fact PipeReader. Response body can be written with BodyWriter (PipeWriter).
  • 43. 43 Span<T> .NET Core 2.1 ReadOnlySpan<T> C# 7.2 ref struct Array Slicing
  • 44. 44 Span<T> - Example N A M E @ E M A I L
  • 45. 45 Span<T> - Example N A M E @ E M A I L public ReadOnlySpan<char> GetName(ReadOnlySpan<char> email) { var @position = email.LastIndexOf(‘@’); return @position == -1 ? ReadOnlySpan<char>.Empty : email.Slice(0, @position); }
  • 46. 46 Span<T> - Two versions Background vector Created by brgfx - www.freepik.com
  • 47. 47 Span<T> - Two versions Method Job Mean StdDev SpanIndexer_Get .NET 4.6 0.6054 ns 0.0007 ns SpanIndexer_Get .NET Core 1.1 0.6047 ns 0.0008 ns SpanIndexer_Get .NET Core 2.0 0.5333 ns 0.0006 ns SpanIndexer_Set .NET 4.6 0.6059 ns 0.0007 ns SpanIndexer_Set .NET Core 1.1 0.6042 ns 0.0002 ns SpanIndexer_Set .NET Core 2.0 0.5205 ns 0.0003 ns Source: Adam Sitnik - https://adamsitnik.com/Span/#using-span
  • 48. 48 Limitations of Span<T> Heap as generic type argument implement any interfaces No parameter of async method
  • 49. 49 Memory<T> .NET Core 2.1 Asynchronous world C# 7.2 ReadOnlyMemory<T> On Heap Wrapper of Span<T>
  • 50. 50 Span<T> and Memory<T> - Supported in .NET Standard 1.0 1.1 1.2 .NET Core 1.0 1.0 1.0 .NET Framework 1 4.5 4.5 4.5.1 Mono 4.6 4.6 4.6 Xamarin.iOS 10.0 10.0 10.0 Xamarin.Mac 3.0 3.0 3.0 Xamarin.Android 7.0 7.0 7.0 Universal Windows Platform 10.0 10.0 10.0 Unity 2018.1 2018.1 2018.1
  • 52. 52 Json.NET – High performance JSON serializer and deserializer .NET Standard 1.6 2.0 2.1 .NET Core 1.0 2.0 3.0 .NET Framework 4.6.1 4.6.1 Won’t support Mono 4.6 5.4 6.4 Xamarin.iOS 10.0 10.14 12.16 Xamarin.Mac 3.0 3.8 5.16 Xamarin.Android 7.0 8.0 10.0 Universal Windows Platform 10.0.16299 10.0. 16299 TBD Unity 2018.1 2018.1 TBD

Editor's Notes

  1. Tu myślałem wyjść od jakiegoś use-case'u. Np mamy jakiś duży plik CSV który chcemy sparsować. Prezentujemy stare podejście na streamach, płynnie przechodząc do System.IO.Pipelines i potem BodyReadera/Writera
  2. Tu myślałem wyjść od jakiegoś use-case'u. Np mamy jakiś duży plik CSV który chcemy sparsować. Prezentujemy stare podejście na streamach, płynnie przechodząc do System.IO.Pipelines i potem BodyReadera/Writera
  3. Tu myślałem wyjść od jakiegoś use-case'u. Np mamy jakiś duży plik CSV który chcemy sparsować. Prezentujemy stare podejście na streamach, płynnie przechodząc do System.IO.Pipelines i potem BodyReadera/Writera
  4. KOD!
  5. Możemy zaalokować większy bufor, jeżeli natrafimy na dłuższą linię lub rekord zawierający kilka linii. Przy okazji można stosować inne sztuczki, np. ArrayPool w celu minimalizowania liczby alokowanych buforów itp. Itd.. No ok. tylko wtedy przy zwiększaniu bufora kopiujemy pamięć. Dodatkowo warto by było potem zmniejszać ten bufor, żeby nie zajmować niepotrzebnie pamięci….pomysł nie do końca trafiony – generuje duże wykorzystanie pamięci. Możemy poprzedni pomysł rozszerzyć o dodawanie dodatkowych buforów tylko wtedy, kiedy poprzedni zostanie wykorzystany. Potrzebujemy wtedy logiki do odczytywania fragmentów pojedynczego rekordu z wielu buforów, oznaczania zwolnionych już buforów (takich z których odczytaliśmy już dane rekordu) itp. Itd. Całość robi się bardzo skomplikowana… A i tak nie jest do końca efektywnie, bo: Odczyt danych ze strumienia jest uzależniony od szybkości parsowania. Wykorzystanie zwykłej zarządzanej tablicy bajtów może mieć impact na GC – pinned memory, może prowadzić do fragmentacji pamięci.
  6. Możemy zaalokować większy bufor, jeżeli natrafimy na dłuższą linię lub rekord zawierający kilka linii. Przy okazji można stosować inne sztuczki, np. ArrayPool w celu minimalizowania liczby alokowanych buforów itp. Itd.. No ok. tylko wtedy przy zwiększaniu bufora kopiujemy pamięć. Dodatkowo warto by było potem zmniejszać ten bufor, żeby nie zajmować niepotrzebnie pamięci….pomysł nie do końca trafiony – generuje duże wykorzystanie pamięci. Możemy poprzedni pomysł rozszerzyć o dodawanie dodatkowych buforów tylko wtedy, kiedy poprzedni zostanie wykorzystany. Potrzebujemy wtedy logiki do odczytywania fragmentów pojedynczego rekordu z wielu buforów, oznaczania zwolnionych już buforów (takich z których odczytaliśmy już dane rekordu) itp. Itd. Całość robi się bardzo skomplikowana… A i tak nie jest do końca efektywnie, bo: Odczyt danych ze strumienia jest uzależniony od szybkości parsowania. Wykorzystanie zwykłej zarządzanej tablicy bajtów może mieć impact na GC – pinned memory, może prowadzić do fragmentacji pamięci.
  7. Pipe składa się z dwóch części: PipeWriter – który zapisuje do naszej „rury” oraz PipeReader, który z tej „rury” czyta. Mamy ładnie podzielony proces na 2 składowe – załadowanie danych ze strumienia oraz parsowanie tych danych. Task.WhenAll wskazuje, że obie składowe będą wykonywały się asynchronicznie.
  8. Pipe składa się z dwóch części: PipeWriter – który zapisuje do naszej „rury” oraz PipeReader, który z tej „rury” czyta. Mamy ładnie podzielony proces na 2 składowe – załadowanie danych ze strumienia oraz parsowanie tych danych. Task.WhenAll wskazuje, że obie składowe będą wykonywały się asynchronicznie. KOD
  9. Jedną z największych zalet wykorzystanie Pipe’ów jest Partial Read – możemy w zasadzie pracować na danych bez ich „skonsumowania”. Przykład ilustruje przykładowy parser HTTP.
  10. Pod maską Pipe zarządza (linked) listą zaalokowanych buforów, które są wykorzystywane przez PipeWritera/PipeReadera. PipeReader.ReadAsync zwraca ReadOnlySequence<T>. Za jego pomocą możemy uzyskać dostęp do jednego lub więcej segmentów pamięci (ReadOnlyMemory<T>) – analogicznie do Span<T> i Memory<T> i stringów. Pipe przechowuje informację o położeniu Writera i Readera w kontekście zaalokowanych danych z wykorzystaniem SequencePosition. SequencePosition to nic innego jak wskaźnik na konkretne miejsce we wspomnianej linked liście. ReadOnlySequence<T> i Sequence position to struktury.
  11. W idealnym przypadku to co przychodzi do serwera jest odczytywane przez jeden z wątków i jednocześnie parsowane i przetwarzane przez inny wątek. Samo parsowanie może jednak trwać znacznie dłużej niż ładowanie danych ze strumienia. W tej sytuacji wątek ładujący dane ze strumienia może albo alokować więcej pamięci, albo wstrzymać pracę na jakiś czas - należy znaleźć odpowiedni balans w celu zapewnienia optymalnej wydajności. Do rozwiązania wspomnianego problemu Pipy zostały wyposażone w 2 właściwości – PauseWriterThreshold i ResumeWriterThreshold. Pierwsza definiuje ile danych powinno zostać zbuforowanych zanim wywołanie metody FlushAsync (PipeWriter) spowoduje wstrzymanie pracy Writera. Druga z kolei kontroluje ilość danych którą może zostać skonsumowanych przez PipeReadera zanim praca PipeWritera zostanie wznowiona.
  12. W idealnym przypadku to co przychodzi do serwera jest odczytywane przez jeden z wątków i jednocześnie parsowane i przetwarzane przez inny wątek. Samo parsowanie może jednak trwać znacznie dłużej niż ładowanie danych ze strumienia. W tej sytuacji wątek ładujący dane ze strumienia może albo alokować więcej pamięci, albo wstrzymać pracę na jakiś czas - należy znaleźć odpowiedni balans w celu zapewnienia optymalnej wydajności. Do rozwiązania wspomnianego problemu Pipy zostały wyposażone w 2 właściwości – PauseWriterThreshold i ResumeWriterThreshold. Pierwsza definiuje ile danych powinno zostać zbuforowanych zanim wywołanie metody FlushAsync (PipeWriter) spowoduje wstrzymanie pracy Writera. Druga z kolei kontroluje ilość danych którą może zostać skonsumowanych przez PipeReadera zanim praca PipeWritera zostanie wznowiona.
  13. W idealnym przypadku to co przychodzi do serwera jest odczytywane przez jeden z wątków i jednocześnie parsowane i przetwarzane przez inny wątek. Samo parsowanie może jednak trwać znacznie dłużej niż ładowanie danych ze strumienia. W tej sytuacji wątek ładujący dane ze strumienia może albo alokować więcej pamięci, albo wstrzymać pracę na jakiś czas - należy znaleźć odpowiedni balans w celu zapewnienia optymalnej wydajności. Do rozwiązania wspomnianego problemu Pipy zostały wyposażone w 2 właściwości – PauseWriterThreshold i ResumeWriterThreshold. Pierwsza definiuje ile danych powinno zostać zbuforowanych zanim wywołanie metody FlushAsync (PipeWriter) spowoduje wstrzymanie pracy Writera. Druga z kolei kontroluje ilość danych którą może zostać skonsumowanych przez PipeReadera zanim praca PipeWritera zostanie wznowiona.
  14. W idealnym przypadku to co przychodzi do serwera jest odczytywane przez jeden z wątków i jednocześnie parsowane i przetwarzane przez inny wątek. Samo parsowanie może jednak trwać znacznie dłużej niż ładowanie danych ze strumienia. W tej sytuacji wątek ładujący dane ze strumienia może albo alokować więcej pamięci, albo wstrzymać pracę na jakiś czas - należy znaleźć odpowiedni balans w celu zapewnienia optymalnej wydajności. Do rozwiązania wspomnianego problemu Pipy zostały wyposażone w 2 właściwości – PauseWriterThreshold i ResumeWriterThreshold. Pierwsza definiuje ile danych powinno zostać zbuforowanych zanim wywołanie metody FlushAsync (PipeWriter) spowoduje wstrzymanie pracy Writera. Druga z kolei kontroluje ilość danych którą może zostać skonsumowanych przez PipeReadera zanim praca PipeWritera zostanie wznowiona.
  15. W idealnym przypadku to co przychodzi do serwera jest odczytywane przez jeden z wątków i jednocześnie parsowane i przetwarzane przez inny wątek. Samo parsowanie może jednak trwać znacznie dłużej niż ładowanie danych ze strumienia. W tej sytuacji wątek ładujący dane ze strumienia może albo alokować więcej pamięci, albo wstrzymać pracę na jakiś czas - należy znaleźć odpowiedni balans w celu zapewnienia optymalnej wydajności. Do rozwiązania wspomnianego problemu Pipy zostały wyposażone w 2 właściwości – PauseWriterThreshold i ResumeWriterThreshold. Pierwsza definiuje ile danych powinno zostać zbuforowanych zanim wywołanie metody FlushAsync (PipeWriter) spowoduje wstrzymanie pracy Writera. Druga z kolei kontroluje ilość danych którą może zostać skonsumowanych przez PipeReadera zanim praca PipeWritera zostanie wznowiona.
  16. W idealnym przypadku to co przychodzi do serwera jest odczytywane przez jeden z wątków i jednocześnie parsowane i przetwarzane przez inny wątek. Samo parsowanie może jednak trwać znacznie dłużej niż ładowanie danych ze strumienia. W tej sytuacji wątek ładujący dane ze strumienia może albo alokować więcej pamięci, albo wstrzymać pracę na jakiś czas - należy znaleźć odpowiedni balans w celu zapewnienia optymalnej wydajności. Do rozwiązania wspomnianego problemu Pipy zostały wyposażone w 2 właściwości – PauseWriterThreshold i ResumeWriterThreshold. Pierwsza definiuje ile danych powinno zostać zbuforowanych zanim wywołanie metody FlushAsync (PipeWriter) spowoduje wstrzymanie pracy Writera. Druga z kolei kontroluje ilość danych którą może zostać skonsumowanych przez PipeReadera zanim praca PipeWritera zostanie wznowiona.
  17. W idealnym przypadku to co przychodzi do serwera jest odczytywane przez jeden z wątków i jednocześnie parsowane i przetwarzane przez inny wątek. Samo parsowanie może jednak trwać znacznie dłużej niż ładowanie danych ze strumienia. W tej sytuacji wątek ładujący dane ze strumienia może albo alokować więcej pamięci, albo wstrzymać pracę na jakiś czas - należy znaleźć odpowiedni balans w celu zapewnienia optymalnej wydajności. Do rozwiązania wspomnianego problemu Pipy zostały wyposażone w 2 właściwości – PauseWriterThreshold i ResumeWriterThreshold. Pierwsza definiuje ile danych powinno zostać zbuforowanych zanim wywołanie metody FlushAsync (PipeWriter) spowoduje wstrzymanie pracy Writera. Druga z kolei kontroluje ilość danych którą może zostać skonsumowanych przez PipeReadera zanim praca PipeWritera zostanie wznowiona.
  18. W idealnym przypadku to co przychodzi do serwera jest odczytywane przez jeden z wątków i jednocześnie parsowane i przetwarzane przez inny wątek. Samo parsowanie może jednak trwać znacznie dłużej niż ładowanie danych ze strumienia. W tej sytuacji wątek ładujący dane ze strumienia może albo alokować więcej pamięci, albo wstrzymać pracę na jakiś czas - należy znaleźć odpowiedni balans w celu zapewnienia optymalnej wydajności. Do rozwiązania wspomnianego problemu Pipy zostały wyposażone w 2 właściwości – PauseWriterThreshold i ResumeWriterThreshold. Pierwsza definiuje ile danych powinno zostać zbuforowanych zanim wywołanie metody FlushAsync (PipeWriter) spowoduje wstrzymanie pracy Writera. Druga z kolei kontroluje ilość danych którą może zostać skonsumowanych przez PipeReadera zanim praca PipeWritera zostanie wznowiona.
  19. W idealnym przypadku to co przychodzi do serwera jest odczytywane przez jeden z wątków i jednocześnie parsowane i przetwarzane przez inny wątek. Samo parsowanie może jednak trwać znacznie dłużej niż ładowanie danych ze strumienia. W tej sytuacji wątek ładujący dane ze strumienia może albo alokować więcej pamięci, albo wstrzymać pracę na jakiś czas - należy znaleźć odpowiedni balans w celu zapewnienia optymalnej wydajności. Do rozwiązania wspomnianego problemu Pipy zostały wyposażone w 2 właściwości – PauseWriterThreshold i ResumeWriterThreshold. Pierwsza definiuje ile danych powinno zostać zbuforowanych zanim wywołanie metody FlushAsync (PipeWriter) spowoduje wstrzymanie pracy Writera. Druga z kolei kontroluje ilość danych którą może zostać skonsumowanych przez PipeReadera zanim praca PipeWritera zostanie wznowiona.
  20. W idealnym przypadku to co przychodzi do serwera jest odczytywane przez jeden z wątków i jednocześnie parsowane i przetwarzane przez inny wątek. Samo parsowanie może jednak trwać znacznie dłużej niż ładowanie danych ze strumienia. W tej sytuacji wątek ładujący dane ze strumienia może albo alokować więcej pamięci, albo wstrzymać pracę na jakiś czas - należy znaleźć odpowiedni balans w celu zapewnienia optymalnej wydajności. Do rozwiązania wspomnianego problemu Pipy zostały wyposażone w 2 właściwości – PauseWriterThreshold i ResumeWriterThreshold. Pierwsza definiuje ile danych powinno zostać zbuforowanych zanim wywołanie metody FlushAsync (PipeWriter) spowoduje wstrzymanie pracy Writera. Druga z kolei kontroluje ilość danych którą może zostać skonsumowanych przez PipeReadera zanim praca PipeWritera zostanie wznowiona.
  21. W idealnym przypadku to co przychodzi do serwera jest odczytywane przez jeden z wątków i jednocześnie parsowane i przetwarzane przez inny wątek. Samo parsowanie może jednak trwać znacznie dłużej niż ładowanie danych ze strumienia. W tej sytuacji wątek ładujący dane ze strumienia może albo alokować więcej pamięci, albo wstrzymać pracę na jakiś czas - należy znaleźć odpowiedni balans w celu zapewnienia optymalnej wydajności. Do rozwiązania wspomnianego problemu Pipy zostały wyposażone w 2 właściwości – PauseWriterThreshold i ResumeWriterThreshold. Pierwsza definiuje ile danych powinno zostać zbuforowanych zanim wywołanie metody FlushAsync (PipeWriter) spowoduje wstrzymanie pracy Writera. Druga z kolei kontroluje ilość danych którą może zostać skonsumowanych przez PipeReadera zanim praca PipeWritera zostanie wznowiona.
  22. Oczywiście w 99% przypadków wgl nie będziemy zajmowali się samodzielnym parsowaniem treści Body. Warto jednak wiedzieć jak to działa pod maską.
  23. Oczywiście w 99% przypadków wgl nie będziemy zajmowali się samodzielnym parsowaniem treści Body. Warto jednak wiedzieć jak to działa pod maską.
  24. Oczywiście w 99% przypadków wgl nie będziemy zajmowali się samodzielnym parsowaniem treści Body. Warto jednak wiedzieć jak to działa pod maską.
  25. Oczywiście w 99% przypadków wgl nie będziemy zajmowali się samodzielnym parsowaniem treści Body. Warto jednak wiedzieć jak to działa pod maską.