SlideShare a Scribd company logo
History of asynchronous in .NET
Tour around evolution of asynchronous computing in .NET
Marcin Tyborowski
• .NET Developer at Billennium
• Speaker
• Co-organizer of Programisotk
Why should I analyze the history?
• Better understanding of concept
• See why this mechanism took its current form
async await
Agenda
• Async programming basics
• History of asynchronous in .NET
• A lot of complaints
• Some WTF’s
• What lies beneath
Async programming
writing computer programs so that events happen
outside of the main program flow, in the same
overlapping time frame.
Asynchronous models
Multiple machines
Multiple processes
Multiple threads
Thread Thread
Thread Thread
Heap memory
All of these have their place in complex
systems, and different languages, platforms,
and technologies tend to favor a particular
model
Concurrency vs parallelism
Concurrency is about dealing with lots of things at
once.
Parallelism is about doing lots of things at once.
History of asynchronous in .NET
History of asynchronous in .NET
What’s new?
• Thread
• ThreadPool
System.Threading namespace
Thread
• Simple API for dealing with thread
• 1:1 map to OS thread
• Foreground & background
• A lot of control == a lot of work
class Program
{
static void Main(string[] args)
{
Thread thread1 = new Thread(ThreadWork.DoWork);
thread1.Start();
}
}
public class ThreadWork
{
public static void DoWork()
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine("Working thread...");
Thread.Sleep(100);
}
}
}
Console.WriteLine($"Current AppDomain: {Thread.GetDomain().FriendlyName}");
Console.WriteLine($"Current Context Id: {Thread.CurrentContext.ContextID}");
Console.WriteLine($"Thread name: {Thread.CurrentThread.Name}");
Console.WriteLine($"Is alive?: {Thread.CurrentThread.IsAlive}");
Console.WriteLine($"State: {Thread.CurrentThread.ThreadState}");
Console.WriteLine($"Priority: {Thread.CurrentThread.Priority}");
ThreadPool
• Linked list of work items
• Reuse created threads
• Minimalize responsibility of thread
management
class Program
{
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(ThreadWork.DoWorkInThreadPool);
}
}
public class ThreadWork
{
public static void DoWorkInThreadPool(object stateInfo)
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine("Hello from threadpool...");
Thread.Sleep(100);
}
}
}
What’s wrong?
• Thread is expensive to create
• Uncontroller threads creation
can cause consuming memory
• Working with ThreadPool is still
very complex
Asynchronous Programming Model APM
• Introduced with .NET 1.1
• Simplifies working with ThreadPool
• Pair of methods and call object
static void Main(string[] args)
{
AddictionDelegate add = AddOperation;
IAsyncResult result =
add.BeginInvoke(10, 5, new AsyncCallback(AddOperationComplete), "someData");
int operationResult = add.EndInvoke(result);
}
static int AddOperation(int a, int b)
{
return a + b;
}
static void AddOperationComplete(IAsyncResult ar)
{
Console.WriteLine($"Write {ar.AsyncState}");
Console.WriteLine($"ThreadId: { Thread.CurrentThread.ManagedThreadId}");
}
static void Main(string[] args)
{
AddictionDelegate add = AddOperation;
IAsyncResult result =
add.BeginInvoke(10, 5, new AsyncCallback(AddOperationComplete), "someData");
int operationResult = add.EndInvoke(result);
}
static int AddOperation(int a, int b)
{
return a + b;
}
static void AddOperationComplete(IAsyncResult ar)
{
Console.WriteLine($"Write {ar.AsyncState}");
Console.WriteLine($"ThreadId: { Thread.CurrentThread.ManagedThreadId}");
}
static void Main(string[] args)
{
AddictionDelegate add = AddOperation;
IAsyncResult result =
add.BeginInvoke(10, 5, new AsyncCallback(AddOperationComplete), "someData");
int operationResult = add.EndInvoke(result);
}
static int AddOperation(int a, int b)
{
return a + b;
}
static void AddOperationComplete(IAsyncResult ar)
{
Console.WriteLine($"Write {ar.AsyncState}");
Console.WriteLine($"ThreadId: { Thread.CurrentThread.ManagedThreadId}");
}
What’s wrong?
• APM make async code very
different from sync code
• Need to run End___ method to
clean up allocated resources
• Problems with GUI apps
• .NET Core?
History of asynchronous in .NET
History of asynchronous in .NET
What’s new?
• Synchronization Context
• Event-based Asynchronous Pattern EAP
Synchronization Context
• Unification dealing with UI thread in WinForms, WPF, Silverlight
• While initialization UI creates instance of SynchronizationContext
Deadlock?
public void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var result = SomeAsyncMethod().Result;
resultTB.Text = result;
}
public async Task<string> SomeAsyncMethod()
{
var result = await FetchDataAsync();
return result;
}
public void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var result = SomeAsyncMethod().Result;
resultTB.Text = result;
}
public async Task<string> SomeAsyncMethod()
{
var result = await FetchDataAsync();
return result;
}
public void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var result = SomeAsyncMethod().Result;
resultTB.Text = result;
}
public async Task<string> SomeAsyncMethod()
{
var result = await FetchDataAsync().ConfigureAwait(false);
return result;
}
Event-based Aysynchronous Pattern
• Each operation has
• method to start async work
• event that fires when operation is completed
• Improve error handling
• Resolve UI interaction problems
public event CalculationHandler CalculationCompleted;
private void RunCalculation(object sender, RoutedEventArgs e)
{
CalculationCompleted += OnCalculationCompleted;
CalculateSomething(10, 20, sender, new CalculatorEventArgs());
}
private void CalculateSomething(int a, int b, object sender, CalculatorEventArgs
e)
{
e.Result = a + b;
CalculationCompleted.Invoke(sender, e);
}
private void OnCalculationCompleted(object sender, CalculatorEventArgs e)
{
ResultLabel.Text = e.Result.ToString();
CalculationCompleted -= OnCalculationCompleted;
}
public event CalculationHandler CalculationCompleted;
private void RunCalculation(object sender, RoutedEventArgs e)
{
CalculationCompleted += OnCalculationCompleted;
CalculateSomething(10, 20, sender, new CalculatorEventArgs());
}
private void CalculateSomething(int a, int b, object sender, CalculatorEventArgs
e)
{
e.Result = a + b;
CalculationCompleted.Invoke(sender, e);
}
private void OnCalculationCompleted(object sender, CalculatorEventArgs e)
{
ResultLabel.Text = e.Result.ToString();
CalculationCompleted -= OnCalculationCompleted;
}
public event CalculationHandler CalculationCompleted;
private void RunCalculation(object sender, RoutedEventArgs e)
{
CalculationCompleted += OnCalculationCompleted;
CalculateSomething(10, 20, sender, new CalculatorEventArgs());
}
private void CalculateSomething(int a, int b, object sender, CalculatorEventArgs
e)
{
e.Result = a + b;
CalculationCompleted.Invoke(sender, e);
}
private void OnCalculationCompleted(object sender, CalculatorEventArgs e)
{
ResultLabel.Text = e.Result.ToString();
CalculationCompleted -= OnCalculationCompleted;
}
private void RunCalculation(object sender, RoutedEventArgs e)
{
CalculationCompleted += OnCalculationCompleted;
Thread t = new Thread(() => CalculateSomething(10, 20, sender, new
CalculatorEventArgs()));
t.Start();
}
private void OnCalculationCompleted(object sender, CalculatorEventArgs e)
{
Dispatcher.Invoke(() =>
{
ResultLabel.Text = e.Result.ToString();
});
CalculationCompleted -= OnCalculationCompleted;
}
private void RunCalculation(object sender, RoutedEventArgs e)
{
CalculationCompleted += OnCalculationCompleted;
Thread t = new Thread(() => CalculateSomething(10, 20, sender, new
CalculatorEventArgs()));
t.Start();
}
private void OnCalculationCompleted(object sender, CalculatorEventArgs e)
{
Dispatcher.Invoke(() =>
{
ResultLabel.Text = e.Result.ToString();
});
CalculationCompleted -= OnCalculationCompleted;
}
Error handling
private void CalculateSomething(int a, int b, object sender,
CalculatorEventArgs e)
{
try
{
e.Result = a + b;
}
catch (Exception ex)
{
e.Error = ex.Message;
}
finally
{
CalculationCompleted.Invoke(sender, e);
}
}
private void OnCalculationCompleted(object sender,
CalculatorEventArgs e)
{
if (e.Error == null)
// Update UI
else
// Log error
CalculationCompleted -= OnCalculationCompleted;
}
What’s wrong?
• Still async code is very
different from sync code
• A lot of elements to implement
and be aware of
History of asynchronous in .NET
What’s new?
• Lambda expressions
delegate int FuncForString(string text);
// C# 1.0 delegate type and delegate instance
FuncForString fun1 = new FuncForString(GetStringLength);
delegate int FuncForString(string text);
// C# 2.0 method group conversion
FuncForString fun2 = GetStringLength;
// C# 2.0 generic delegate and anonymous method
Func<string, int> fun3 = delegate (string text)
{ return text.Length; };
// C# 3.0 lamba expression
Func<string, int> fun4 = (string text) =>
{ return text.Length; };
// C# 3.0 no need unnecessary parentheses
Func<string, int> fun7 = text => text.Length;
History of asynchronous in .NET
What’s new?
• ThreadPool queue remodelling
• Work stealing queues
• Task Parallel Libarary TPL
ThreadPool queue remodelling
Work stealing queues
Task Parallel Library
• Set of software APIs in the System.Threading.Tasks
• Task represents an asynchronous unit of work
• Easier to use for developers
Compute-based task
• Abstraction for OS thread
• Two possibilities
• Create new thread
• Schedule work on reusable ThreadPool
• Task.Run
• TaskFactory.StartNew
static void Main(string[] args)
{
Task t = new Task(Speak);
t.Start();
Console.WriteLine("Waiting for completion");
t.Wait();
Console.ReadKey();
}
private static void Speak()
{
Console.WriteLine("Hello world");
}
static void Main(string[] args)
{
Task t1 = Task.Run(Speak);
Task t2 = Task.Factory.StartNew(Speak);
Console.WriteLine("Waiting for completion");
t1.Wait();
t2.Wait();
}
private static void Speak()
{
Console.WriteLine("Hello world");
}
static void Main(string[] args)
{
var message = "Hello World";
Task t1 = Task.Run(() => SpeakWithParam(message));
Task t2 = Task.Factory.StartNew(() => SpeakWithParam(message));
Console.WriteLine("Waiting for completion");
t1.Wait();
t2.Wait();
}
private static void SpeakWithParam(string textToSpeak)
{
Console.WriteLine(textToSpeak);
}
for (int i = 0; i < 10; i++)
{
Task.Factory.StartNew(() => Console.WriteLine(i));
}
History of asynchronous in .NET
for (int i = 0; i < 10; i++)
{
int captureI = i;
Task.Factory.StartNew(() => Console.WriteLine(captureI));
}
History of asynchronous in .NET
I/O-based task
• Ask for external resource and do other things while waiting for
completion
static void Main(string[] args)
{
var url = "https://google.com";
Task task1 = Task.Factory.StartNew(() => DownloadWebPage(url));
// synchronous operations
task1.Wait();
Console.ReadKey();
}
private static string DownloadWebPage(string url)
{
WebRequest request = WebRequest.Create(url);
WebResponse response = request.GetResponse();
var reader = new StreamReader(response.GetResponseStream());
{
return reader.ReadToEnd();
}
}
static void Main(string[] args)
{
var url = "https://google.com";
Task task1 = Task.Factory.StartNew(() => DownloadWebPage(url));
// synchronous operations
task1.Wait();
Console.ReadKey();
}
private static string DownloadWebPage(string url)
{
WebRequest request = WebRequest.Create(url);
WebResponse response = request.GetResponse();
var reader = new StreamReader(response.GetResponseStream());
{
return reader.ReadToEnd();
}
}
Child tasks
• Parent wait for child
completion
Chained tasks
• ContinueWith
Task
Task Task Task
Task Task Task
What’s wrong?
• Code is still different
from sync code
History of asynchronous in .NET
What’s new?
• Task-based Asynchronous Pattern
• async/await
• Wait()s, Results no longer needed
static async Task<int> TestAsync()
{
Task<int> firstTask = GetNumberAsync(1);
Task<int> secondTask = GetNumberAsync(2);
Task<int> thirdTask = GetNumberAsync(4);
// some synchronous operations
var firstResult = await firstTask;
var secondResult = await secondTask;
var thirdResult = await thirdTask;
return firstResult + secondResult + thirdResult;
}
public static async Task<int> GetNumberAsync(int number)
=> await Task.Run(() => number);
static async Task<int> TestAsync()
{
Task<int> firstTask = GetNumberAsync(1);
Task<int> secondTask = GetNumberAsync(2);
Task<int> thirdTask = GetNumberAsync(4);
// some synchronous operations
var firstResult = await firstTask;
var secondResult = await secondTask;
var thirdResult = await thirdTask;
return firstResult + secondResult + thirdResult;
}
public static async Task<int> GetNumberAsync(int number)
=> await Task.Run(() => number);
History of asynchronous in .NET
[CompilerGenerated]
[StructLayout(LayoutKind.Auto)]
private struct <TestAsync>d__1 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder<int> <>t__builder;
private int <firstResult>5__2;
private int <secondResult>5__3;
private TaskAwaiter<int> <>u__1;
void IAsyncStateMachine.MoveNext()
{
int num = this.<>1__state;
int result2;
try
{
TaskAwaiter<int> awaiter;
switch (num)
{
case 1:
awaiter = this.<>u__1;
this.<>u__1 = default(TaskAwaiter<int>);
this.<>1__state = -1;
goto IL_E1;
case 2:
awaiter = this.<>u__1;
this.<>u__1 = default(TaskAwaiter<int>);
this.<>1__state = -1;
goto IL_14F;
default:
// some code
break;
}
}
IL_E1:
result = awaiter.GetResult();
this.<secondResult>5__3 = result;
Console.WriteLine(this.<secondResult>5__3);
awaiter = Program.GetNumberAsync(4).GetAwaiter();
if (!awaiter.IsCompleted)
{
this.<>1__state = 2;
this.<>u__1 = awaiter;
this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<int>,
Program.<TestAsync>d__1>(ref awaiter, ref this);
return;
}
IL_14F:
int thirdResult = awaiter.GetResult();
Console.WriteLine("I'm done");
result2 = this.<firstResult>5__2 + this.<secondResult>5__3 +
thirdResult;
IL_E1:
result = awaiter.GetResult();
this.<secondResult>5__3 = result;
Console.WriteLine(this.<secondResult>5__3);
awaiter = Program.GetNumberAsync(4).GetAwaiter();
if (!awaiter.IsCompleted)
{
this.<>1__state = 2;
this.<>u__1 = awaiter;
this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<int>,
Program.<TestAsync>d__1>(ref awaiter, ref this);
return;
}
IL_14F:
int thirdResult = awaiter.GetResult();
Console.WriteLine("I'm done");
result2 = this.<firstResult>5__2 + this.<secondResult>5__3 +
thirdResult;
Summary
• What lies underneath
• Better understanding of concepts
• 95% cases don’t apply
• What about these 5%
Summary
• What lies underneath
• Better understanding of concepts
• 95% cases don’t apply
• What about these 5%
• Avoid Wait() and
GetAwaiter().GetResult()
History of asynchronous in .NET
Links
https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
https://foreverframe.net/what-lies-beneath-asyncawait-in-c/
https://github.com/tbr09/Multithreading
https://www.youtube.com/watch?v=ZvglMATXP6o
https://codingcanvas.com/history-of-asynchronous-programming-
models-in-net-framework/
https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-
programming-patterns/task-based-asynchronous-pattern-tap
Thanks for your attention 
@mtyborowski09 @tbr09mtyborowski09@gmail.com

More Related Content

PPTX
[Webinar] Qt Test-Driven Development Using Google Test and Google Mock
 
PDF
LLVM Register Allocation
PPTX
Java 11 to 17 : What's new !?
PDF
Clean code
PPTX
Qt test framework
 
PDF
Q4.11: Using GCC Auto-Vectorizer
PDF
Kernel Recipes 2015: Kernel packet capture technologies
PDF
パッケージングを支える技術 pyconjp2016
[Webinar] Qt Test-Driven Development Using Google Test and Google Mock
 
LLVM Register Allocation
Java 11 to 17 : What's new !?
Clean code
Qt test framework
 
Q4.11: Using GCC Auto-Vectorizer
Kernel Recipes 2015: Kernel packet capture technologies
パッケージングを支える技術 pyconjp2016

What's hot (20)

PDF
Interpreter, Compiler, JIT from scratch
PDF
Switch Transformers: Scaling to Trillion Parameter Models with Simple and Eff...
PDF
[Webinar] QtSerialBus: Using Modbus and CAN bus with Qt
 
PDF
20分くらいでわかった気分になれるC++20コルーチン
DOCX
Continuous Integration vs Continuous Delivery vs Continuous Deployment
PDF
Doma SQLテンプレートのしくみ
PDF
PHP-FPM の子プロセス制御方法と設定をおさらいしよう
PDF
LLVM Register Allocation (2nd Version)
PPTX
Qt Memory Management & Signal and Slots
PDF
BPF - in-kernel virtual machine
PDF
実践 NestJS
PDF
Bbl sur les tests
PPT
Regular Expressions
PPTX
Clean code slide
PDF
Java 8 Lambda Expressions
PDF
Domain Modeling Made Functional (DevTernity 2022)
PDF
Modern Kernel Pool Exploitation: Attacks and Techniques
PPTX
C# 8.0 非同期ストリーム
PDF
QVariant, QObject — Qt's not just for GUI development
 
PPTX
Clean code
Interpreter, Compiler, JIT from scratch
Switch Transformers: Scaling to Trillion Parameter Models with Simple and Eff...
[Webinar] QtSerialBus: Using Modbus and CAN bus with Qt
 
20分くらいでわかった気分になれるC++20コルーチン
Continuous Integration vs Continuous Delivery vs Continuous Deployment
Doma SQLテンプレートのしくみ
PHP-FPM の子プロセス制御方法と設定をおさらいしよう
LLVM Register Allocation (2nd Version)
Qt Memory Management & Signal and Slots
BPF - in-kernel virtual machine
実践 NestJS
Bbl sur les tests
Regular Expressions
Clean code slide
Java 8 Lambda Expressions
Domain Modeling Made Functional (DevTernity 2022)
Modern Kernel Pool Exploitation: Attacks and Techniques
C# 8.0 非同期ストリーム
QVariant, QObject — Qt's not just for GUI development
 
Clean code
Ad

Similar to History of asynchronous in .NET (20)

PPTX
.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund
DOCX
Asynchronyin net
PPTX
NDC Sydney 2019 - Async Demystified -- Karel Zikmund
PPSX
Async-await best practices in 10 minutes
PDF
Asynchronous programming in .net 4.5 with c#
PPTX
Training – Going Async
PDF
.NET Multithreading and File I/O
PPTX
Async await
PPTX
Task parallel library presentation
PDF
Async Await for Mobile Apps
PPTX
Binary Studio Academy: Concurrency in C# 5.0
PPT
Asynchronous Programming in C# - Part 1
PPTX
C# 5 deep drive into asynchronous programming
PPTX
Async CTP 3 Presentation for MUGH 2012
PPTX
End to-end async and await
PPTX
Async/Await
PPTX
Async Programming in C# 5
PPTX
Async programming in c#
PDF
Why async matters
PPTX
The 3 VS Threading Rules
.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund
Asynchronyin net
NDC Sydney 2019 - Async Demystified -- Karel Zikmund
Async-await best practices in 10 minutes
Asynchronous programming in .net 4.5 with c#
Training – Going Async
.NET Multithreading and File I/O
Async await
Task parallel library presentation
Async Await for Mobile Apps
Binary Studio Academy: Concurrency in C# 5.0
Asynchronous Programming in C# - Part 1
C# 5 deep drive into asynchronous programming
Async CTP 3 Presentation for MUGH 2012
End to-end async and await
Async/Await
Async Programming in C# 5
Async programming in c#
Why async matters
The 3 VS Threading Rules
Ad

Recently uploaded (20)

PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PPT
Teaching material agriculture food technology
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
KodekX | Application Modernization Development
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Unlocking AI with Model Context Protocol (MCP)
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PPTX
Big Data Technologies - Introduction.pptx
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
cuic standard and advanced reporting.pdf
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Programs and apps: productivity, graphics, security and other tools
Dropbox Q2 2025 Financial Results & Investor Presentation
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Digital-Transformation-Roadmap-for-Companies.pptx
Teaching material agriculture food technology
Diabetes mellitus diagnosis method based random forest with bat algorithm
KodekX | Application Modernization Development
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Encapsulation_ Review paper, used for researhc scholars
Unlocking AI with Model Context Protocol (MCP)
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Spectral efficient network and resource selection model in 5G networks
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
20250228 LYD VKU AI Blended-Learning.pptx
Advanced methodologies resolving dimensionality complications for autism neur...
Big Data Technologies - Introduction.pptx
“AI and Expert System Decision Support & Business Intelligence Systems”
cuic standard and advanced reporting.pdf
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf

History of asynchronous in .NET

  • 1. History of asynchronous in .NET Tour around evolution of asynchronous computing in .NET
  • 2. Marcin Tyborowski • .NET Developer at Billennium • Speaker • Co-organizer of Programisotk
  • 3. Why should I analyze the history? • Better understanding of concept • See why this mechanism took its current form
  • 5. Agenda • Async programming basics • History of asynchronous in .NET • A lot of complaints • Some WTF’s • What lies beneath
  • 6. Async programming writing computer programs so that events happen outside of the main program flow, in the same overlapping time frame.
  • 11. All of these have their place in complex systems, and different languages, platforms, and technologies tend to favor a particular model
  • 13. Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once.
  • 16. What’s new? • Thread • ThreadPool System.Threading namespace
  • 17. Thread • Simple API for dealing with thread • 1:1 map to OS thread • Foreground & background • A lot of control == a lot of work
  • 18. class Program { static void Main(string[] args) { Thread thread1 = new Thread(ThreadWork.DoWork); thread1.Start(); } } public class ThreadWork { public static void DoWork() { for (int i = 0; i < 3; i++) { Console.WriteLine("Working thread..."); Thread.Sleep(100); } } }
  • 19. Console.WriteLine($"Current AppDomain: {Thread.GetDomain().FriendlyName}"); Console.WriteLine($"Current Context Id: {Thread.CurrentContext.ContextID}"); Console.WriteLine($"Thread name: {Thread.CurrentThread.Name}"); Console.WriteLine($"Is alive?: {Thread.CurrentThread.IsAlive}"); Console.WriteLine($"State: {Thread.CurrentThread.ThreadState}"); Console.WriteLine($"Priority: {Thread.CurrentThread.Priority}");
  • 20. ThreadPool • Linked list of work items • Reuse created threads • Minimalize responsibility of thread management
  • 21. class Program { static void Main(string[] args) { ThreadPool.QueueUserWorkItem(ThreadWork.DoWorkInThreadPool); } } public class ThreadWork { public static void DoWorkInThreadPool(object stateInfo) { for (int i = 0; i < 3; i++) { Console.WriteLine("Hello from threadpool..."); Thread.Sleep(100); } } }
  • 22. What’s wrong? • Thread is expensive to create • Uncontroller threads creation can cause consuming memory • Working with ThreadPool is still very complex
  • 23. Asynchronous Programming Model APM • Introduced with .NET 1.1 • Simplifies working with ThreadPool • Pair of methods and call object
  • 24. static void Main(string[] args) { AddictionDelegate add = AddOperation; IAsyncResult result = add.BeginInvoke(10, 5, new AsyncCallback(AddOperationComplete), "someData"); int operationResult = add.EndInvoke(result); } static int AddOperation(int a, int b) { return a + b; } static void AddOperationComplete(IAsyncResult ar) { Console.WriteLine($"Write {ar.AsyncState}"); Console.WriteLine($"ThreadId: { Thread.CurrentThread.ManagedThreadId}"); }
  • 25. static void Main(string[] args) { AddictionDelegate add = AddOperation; IAsyncResult result = add.BeginInvoke(10, 5, new AsyncCallback(AddOperationComplete), "someData"); int operationResult = add.EndInvoke(result); } static int AddOperation(int a, int b) { return a + b; } static void AddOperationComplete(IAsyncResult ar) { Console.WriteLine($"Write {ar.AsyncState}"); Console.WriteLine($"ThreadId: { Thread.CurrentThread.ManagedThreadId}"); }
  • 26. static void Main(string[] args) { AddictionDelegate add = AddOperation; IAsyncResult result = add.BeginInvoke(10, 5, new AsyncCallback(AddOperationComplete), "someData"); int operationResult = add.EndInvoke(result); } static int AddOperation(int a, int b) { return a + b; } static void AddOperationComplete(IAsyncResult ar) { Console.WriteLine($"Write {ar.AsyncState}"); Console.WriteLine($"ThreadId: { Thread.CurrentThread.ManagedThreadId}"); }
  • 27. What’s wrong? • APM make async code very different from sync code • Need to run End___ method to clean up allocated resources • Problems with GUI apps • .NET Core?
  • 30. What’s new? • Synchronization Context • Event-based Asynchronous Pattern EAP
  • 31. Synchronization Context • Unification dealing with UI thread in WinForms, WPF, Silverlight • While initialization UI creates instance of SynchronizationContext
  • 33. public void ButtonBase_OnClick(object sender, RoutedEventArgs e) { var result = SomeAsyncMethod().Result; resultTB.Text = result; } public async Task<string> SomeAsyncMethod() { var result = await FetchDataAsync(); return result; }
  • 34. public void ButtonBase_OnClick(object sender, RoutedEventArgs e) { var result = SomeAsyncMethod().Result; resultTB.Text = result; } public async Task<string> SomeAsyncMethod() { var result = await FetchDataAsync(); return result; }
  • 35. public void ButtonBase_OnClick(object sender, RoutedEventArgs e) { var result = SomeAsyncMethod().Result; resultTB.Text = result; } public async Task<string> SomeAsyncMethod() { var result = await FetchDataAsync().ConfigureAwait(false); return result; }
  • 36. Event-based Aysynchronous Pattern • Each operation has • method to start async work • event that fires when operation is completed • Improve error handling • Resolve UI interaction problems
  • 37. public event CalculationHandler CalculationCompleted; private void RunCalculation(object sender, RoutedEventArgs e) { CalculationCompleted += OnCalculationCompleted; CalculateSomething(10, 20, sender, new CalculatorEventArgs()); } private void CalculateSomething(int a, int b, object sender, CalculatorEventArgs e) { e.Result = a + b; CalculationCompleted.Invoke(sender, e); } private void OnCalculationCompleted(object sender, CalculatorEventArgs e) { ResultLabel.Text = e.Result.ToString(); CalculationCompleted -= OnCalculationCompleted; }
  • 38. public event CalculationHandler CalculationCompleted; private void RunCalculation(object sender, RoutedEventArgs e) { CalculationCompleted += OnCalculationCompleted; CalculateSomething(10, 20, sender, new CalculatorEventArgs()); } private void CalculateSomething(int a, int b, object sender, CalculatorEventArgs e) { e.Result = a + b; CalculationCompleted.Invoke(sender, e); } private void OnCalculationCompleted(object sender, CalculatorEventArgs e) { ResultLabel.Text = e.Result.ToString(); CalculationCompleted -= OnCalculationCompleted; }
  • 39. public event CalculationHandler CalculationCompleted; private void RunCalculation(object sender, RoutedEventArgs e) { CalculationCompleted += OnCalculationCompleted; CalculateSomething(10, 20, sender, new CalculatorEventArgs()); } private void CalculateSomething(int a, int b, object sender, CalculatorEventArgs e) { e.Result = a + b; CalculationCompleted.Invoke(sender, e); } private void OnCalculationCompleted(object sender, CalculatorEventArgs e) { ResultLabel.Text = e.Result.ToString(); CalculationCompleted -= OnCalculationCompleted; }
  • 40. private void RunCalculation(object sender, RoutedEventArgs e) { CalculationCompleted += OnCalculationCompleted; Thread t = new Thread(() => CalculateSomething(10, 20, sender, new CalculatorEventArgs())); t.Start(); } private void OnCalculationCompleted(object sender, CalculatorEventArgs e) { Dispatcher.Invoke(() => { ResultLabel.Text = e.Result.ToString(); }); CalculationCompleted -= OnCalculationCompleted; }
  • 41. private void RunCalculation(object sender, RoutedEventArgs e) { CalculationCompleted += OnCalculationCompleted; Thread t = new Thread(() => CalculateSomething(10, 20, sender, new CalculatorEventArgs())); t.Start(); } private void OnCalculationCompleted(object sender, CalculatorEventArgs e) { Dispatcher.Invoke(() => { ResultLabel.Text = e.Result.ToString(); }); CalculationCompleted -= OnCalculationCompleted; }
  • 43. private void CalculateSomething(int a, int b, object sender, CalculatorEventArgs e) { try { e.Result = a + b; } catch (Exception ex) { e.Error = ex.Message; } finally { CalculationCompleted.Invoke(sender, e); } }
  • 44. private void OnCalculationCompleted(object sender, CalculatorEventArgs e) { if (e.Error == null) // Update UI else // Log error CalculationCompleted -= OnCalculationCompleted; }
  • 45. What’s wrong? • Still async code is very different from sync code • A lot of elements to implement and be aware of
  • 48. delegate int FuncForString(string text); // C# 1.0 delegate type and delegate instance FuncForString fun1 = new FuncForString(GetStringLength);
  • 49. delegate int FuncForString(string text); // C# 2.0 method group conversion FuncForString fun2 = GetStringLength;
  • 50. // C# 2.0 generic delegate and anonymous method Func<string, int> fun3 = delegate (string text) { return text.Length; };
  • 51. // C# 3.0 lamba expression Func<string, int> fun4 = (string text) => { return text.Length; };
  • 52. // C# 3.0 no need unnecessary parentheses Func<string, int> fun7 = text => text.Length;
  • 54. What’s new? • ThreadPool queue remodelling • Work stealing queues • Task Parallel Libarary TPL
  • 57. Task Parallel Library • Set of software APIs in the System.Threading.Tasks • Task represents an asynchronous unit of work • Easier to use for developers
  • 58. Compute-based task • Abstraction for OS thread • Two possibilities • Create new thread • Schedule work on reusable ThreadPool • Task.Run • TaskFactory.StartNew
  • 59. static void Main(string[] args) { Task t = new Task(Speak); t.Start(); Console.WriteLine("Waiting for completion"); t.Wait(); Console.ReadKey(); } private static void Speak() { Console.WriteLine("Hello world"); }
  • 60. static void Main(string[] args) { Task t1 = Task.Run(Speak); Task t2 = Task.Factory.StartNew(Speak); Console.WriteLine("Waiting for completion"); t1.Wait(); t2.Wait(); } private static void Speak() { Console.WriteLine("Hello world"); }
  • 61. static void Main(string[] args) { var message = "Hello World"; Task t1 = Task.Run(() => SpeakWithParam(message)); Task t2 = Task.Factory.StartNew(() => SpeakWithParam(message)); Console.WriteLine("Waiting for completion"); t1.Wait(); t2.Wait(); } private static void SpeakWithParam(string textToSpeak) { Console.WriteLine(textToSpeak); }
  • 62. for (int i = 0; i < 10; i++) { Task.Factory.StartNew(() => Console.WriteLine(i)); }
  • 64. for (int i = 0; i < 10; i++) { int captureI = i; Task.Factory.StartNew(() => Console.WriteLine(captureI)); }
  • 66. I/O-based task • Ask for external resource and do other things while waiting for completion
  • 67. static void Main(string[] args) { var url = "https://google.com"; Task task1 = Task.Factory.StartNew(() => DownloadWebPage(url)); // synchronous operations task1.Wait(); Console.ReadKey(); } private static string DownloadWebPage(string url) { WebRequest request = WebRequest.Create(url); WebResponse response = request.GetResponse(); var reader = new StreamReader(response.GetResponseStream()); { return reader.ReadToEnd(); } }
  • 68. static void Main(string[] args) { var url = "https://google.com"; Task task1 = Task.Factory.StartNew(() => DownloadWebPage(url)); // synchronous operations task1.Wait(); Console.ReadKey(); } private static string DownloadWebPage(string url) { WebRequest request = WebRequest.Create(url); WebResponse response = request.GetResponse(); var reader = new StreamReader(response.GetResponseStream()); { return reader.ReadToEnd(); } }
  • 69. Child tasks • Parent wait for child completion Chained tasks • ContinueWith Task Task Task Task Task Task Task
  • 70. What’s wrong? • Code is still different from sync code
  • 72. What’s new? • Task-based Asynchronous Pattern • async/await • Wait()s, Results no longer needed
  • 73. static async Task<int> TestAsync() { Task<int> firstTask = GetNumberAsync(1); Task<int> secondTask = GetNumberAsync(2); Task<int> thirdTask = GetNumberAsync(4); // some synchronous operations var firstResult = await firstTask; var secondResult = await secondTask; var thirdResult = await thirdTask; return firstResult + secondResult + thirdResult; } public static async Task<int> GetNumberAsync(int number) => await Task.Run(() => number);
  • 74. static async Task<int> TestAsync() { Task<int> firstTask = GetNumberAsync(1); Task<int> secondTask = GetNumberAsync(2); Task<int> thirdTask = GetNumberAsync(4); // some synchronous operations var firstResult = await firstTask; var secondResult = await secondTask; var thirdResult = await thirdTask; return firstResult + secondResult + thirdResult; } public static async Task<int> GetNumberAsync(int number) => await Task.Run(() => number);
  • 76. [CompilerGenerated] [StructLayout(LayoutKind.Auto)] private struct <TestAsync>d__1 : IAsyncStateMachine { public int <>1__state; public AsyncTaskMethodBuilder<int> <>t__builder; private int <firstResult>5__2; private int <secondResult>5__3; private TaskAwaiter<int> <>u__1; void IAsyncStateMachine.MoveNext() { int num = this.<>1__state; int result2;
  • 77. try { TaskAwaiter<int> awaiter; switch (num) { case 1: awaiter = this.<>u__1; this.<>u__1 = default(TaskAwaiter<int>); this.<>1__state = -1; goto IL_E1; case 2: awaiter = this.<>u__1; this.<>u__1 = default(TaskAwaiter<int>); this.<>1__state = -1; goto IL_14F; default: // some code break; } }
  • 78. IL_E1: result = awaiter.GetResult(); this.<secondResult>5__3 = result; Console.WriteLine(this.<secondResult>5__3); awaiter = Program.GetNumberAsync(4).GetAwaiter(); if (!awaiter.IsCompleted) { this.<>1__state = 2; this.<>u__1 = awaiter; this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<int>, Program.<TestAsync>d__1>(ref awaiter, ref this); return; } IL_14F: int thirdResult = awaiter.GetResult(); Console.WriteLine("I'm done"); result2 = this.<firstResult>5__2 + this.<secondResult>5__3 + thirdResult;
  • 79. IL_E1: result = awaiter.GetResult(); this.<secondResult>5__3 = result; Console.WriteLine(this.<secondResult>5__3); awaiter = Program.GetNumberAsync(4).GetAwaiter(); if (!awaiter.IsCompleted) { this.<>1__state = 2; this.<>u__1 = awaiter; this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<int>, Program.<TestAsync>d__1>(ref awaiter, ref this); return; } IL_14F: int thirdResult = awaiter.GetResult(); Console.WriteLine("I'm done"); result2 = this.<firstResult>5__2 + this.<secondResult>5__3 + thirdResult;
  • 80. Summary • What lies underneath • Better understanding of concepts • 95% cases don’t apply • What about these 5%
  • 81. Summary • What lies underneath • Better understanding of concepts • 95% cases don’t apply • What about these 5% • Avoid Wait() and GetAwaiter().GetResult()
  • 84. Thanks for your attention  @mtyborowski09 @tbr09mtyborowski09@gmail.com

Editor's Notes

  • #10: Share access to processing cores but dont share memory
  • #16: 13 February 2002 – release of .NET 1.0
  • #32: WinForms – BeginInvoke in Controll class WPF, Silverlight – dispatchers
  • #59: Task.Run TaskFactory.StartNew – we can specify scheduler
  • #60: ThreadPool
  • #63: Kompilator wrzuca lokalna zmienna i do obiektu w stercie zeby mozna bylo sie do niego odwolac. Pytanie kiedy tworzy ten obiekt? i jest deklarowane poza ciałem pętli tak więc obiekt jest tworzony również poza ciałem pętli. Kazdy task dzieli ten obiekt. Pierwszy task zakonczy petle a reszta tasków poprostu wyświetli 10.
  • #64: Kompilator wrzuca lokalna zmienna i do obiektu w stercie. i jest deklarowane poza ciałem Kazdy task dzieli ten obiekt. Pierwszy task zakonczy petle a reszta tasków poprostu wyświetli 10.