├── 01-AsyncDesktop ├── slides │ ├── 03-CodeCompare.PNG │ ├── 01-AsyncDesktopBad.PNG │ └── 02-AsyncDesktopGood.PNG ├── after │ ├── AsyncDesktopDemo │ │ ├── AsyncDesktopDemo.csproj │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── MainWindow.xaml │ │ └── MainWindow.xaml.cs │ └── AsyncDesktopDemo.sln ├── before │ ├── AsyncDesktopDemo │ │ ├── AsyncDesktopDemo.csproj │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── MainWindow.xaml │ │ └── MainWindow.xaml.cs │ └── AsyncDesktopDemo.sln └── README.md ├── 03-AsyncProgressDesktop ├── slides │ ├── 01-Start.png │ ├── 03-Done.png │ └── 02-Progress.png ├── README.md ├── AsyncProgressDesktop │ ├── App.xaml.cs │ ├── AsyncProgressDesktop.csproj │ ├── App.xaml │ ├── Views │ │ ├── MainWindow.xaml │ │ └── MainWindow.xaml.cs │ └── ViewModels │ │ └── MainWindowViewModel.cs └── AsyncProgressDesktop.sln ├── 02-AsyncWebAPI ├── slides │ ├── 05-SyncCode-CPU-bound.PNG │ ├── 06-AsyncCode-CPU-bound.PNG │ ├── review │ │ ├── 04-Parallel-Threads.PNG │ │ ├── T01-Websurge-IO-bound.png │ │ ├── 04-Parallel-Threads-Async.PNG │ │ └── T01-Websurge-IO-bound-Sync.png │ ├── 03-AsyncWebAPI-IO-bound-Code.PNG │ ├── 01-AsyncWebAPI-IO-bound-Compare.PNG │ ├── 02-AsyncWebAPI-IO-bound-CodeSync.PNG │ ├── 04a-AsyncWebAPI-CPU-bound-Compare.PNG │ └── 04b-AsyncWebAPI-CPU-bound-Compare.PNG ├── after │ ├── AsyncWebAPIDemo │ │ ├── appsettings.json │ │ ├── AsyncWebAPIDemo.csproj │ │ ├── appsettings.Development.json │ │ ├── Program.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── Controllers │ │ │ ├── CPUBoundController.cs │ │ │ └── IOBoundController.cs │ │ └── Startup.cs │ └── AsyncWebAPIDemo.sln ├── before │ ├── AsyncWebAPIDemo │ │ ├── appsettings.json │ │ ├── AsyncWebAPIDemo.csproj │ │ ├── appsettings.Development.json │ │ ├── Program.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── Controllers │ │ │ ├── CPUBoundController.cs │ │ │ └── IOBoundController.cs │ │ └── Startup.cs │ └── AsyncWebAPIDemo.sln └── README.md ├── 05-ParallelDemoDesktop ├── ParallelDemoDesktop │ ├── lenna.png │ ├── casabatllo.png │ ├── sagradafamilia.png │ ├── App.xaml.cs │ ├── ParallelDemoDesktop.csproj │ ├── App.xaml │ ├── Views │ │ ├── MainWindow.xaml │ │ └── MainWindow.xaml.cs │ └── ViewModels │ │ └── MainWindowViewModel.cs ├── README.md └── ParallelDemoDesktop.sln ├── 04-AsyncCancelDesktop ├── AsyncCancelDesktop │ ├── App.xaml.cs │ ├── AsyncCancelDesktop.csproj │ ├── App.xaml │ ├── Views │ │ ├── MainWindow.xaml │ │ └── MainWindow.xaml.cs │ ├── CPULoad.cs │ └── ViewModels │ │ └── MainWindowViewModel.cs ├── README.md └── AsyncCancelDesktop.sln ├── README.md └── .gitignore /01-AsyncDesktop/slides/03-CodeCompare.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/01-AsyncDesktop/slides/03-CodeCompare.PNG -------------------------------------------------------------------------------- /03-AsyncProgressDesktop/slides/01-Start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/03-AsyncProgressDesktop/slides/01-Start.png -------------------------------------------------------------------------------- /03-AsyncProgressDesktop/slides/03-Done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/03-AsyncProgressDesktop/slides/03-Done.png -------------------------------------------------------------------------------- /01-AsyncDesktop/slides/01-AsyncDesktopBad.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/01-AsyncDesktop/slides/01-AsyncDesktopBad.PNG -------------------------------------------------------------------------------- /01-AsyncDesktop/slides/02-AsyncDesktopGood.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/01-AsyncDesktop/slides/02-AsyncDesktopGood.PNG -------------------------------------------------------------------------------- /03-AsyncProgressDesktop/slides/02-Progress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/03-AsyncProgressDesktop/slides/02-Progress.png -------------------------------------------------------------------------------- /02-AsyncWebAPI/slides/05-SyncCode-CPU-bound.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/02-AsyncWebAPI/slides/05-SyncCode-CPU-bound.PNG -------------------------------------------------------------------------------- /02-AsyncWebAPI/slides/06-AsyncCode-CPU-bound.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/02-AsyncWebAPI/slides/06-AsyncCode-CPU-bound.PNG -------------------------------------------------------------------------------- /02-AsyncWebAPI/slides/review/04-Parallel-Threads.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/02-AsyncWebAPI/slides/review/04-Parallel-Threads.PNG -------------------------------------------------------------------------------- /05-ParallelDemoDesktop/ParallelDemoDesktop/lenna.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/05-ParallelDemoDesktop/ParallelDemoDesktop/lenna.png -------------------------------------------------------------------------------- /02-AsyncWebAPI/after/AsyncWebAPIDemo/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Warning" 5 | } 6 | }, 7 | "AllowedHosts": "*" 8 | } 9 | -------------------------------------------------------------------------------- /02-AsyncWebAPI/before/AsyncWebAPIDemo/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Warning" 5 | } 6 | }, 7 | "AllowedHosts": "*" 8 | } 9 | -------------------------------------------------------------------------------- /02-AsyncWebAPI/slides/03-AsyncWebAPI-IO-bound-Code.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/02-AsyncWebAPI/slides/03-AsyncWebAPI-IO-bound-Code.PNG -------------------------------------------------------------------------------- /02-AsyncWebAPI/slides/review/T01-Websurge-IO-bound.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/02-AsyncWebAPI/slides/review/T01-Websurge-IO-bound.png -------------------------------------------------------------------------------- /02-AsyncWebAPI/slides/01-AsyncWebAPI-IO-bound-Compare.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/02-AsyncWebAPI/slides/01-AsyncWebAPI-IO-bound-Compare.PNG -------------------------------------------------------------------------------- /02-AsyncWebAPI/slides/02-AsyncWebAPI-IO-bound-CodeSync.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/02-AsyncWebAPI/slides/02-AsyncWebAPI-IO-bound-CodeSync.PNG -------------------------------------------------------------------------------- /02-AsyncWebAPI/slides/review/04-Parallel-Threads-Async.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/02-AsyncWebAPI/slides/review/04-Parallel-Threads-Async.PNG -------------------------------------------------------------------------------- /05-ParallelDemoDesktop/ParallelDemoDesktop/casabatllo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/05-ParallelDemoDesktop/ParallelDemoDesktop/casabatllo.png -------------------------------------------------------------------------------- /02-AsyncWebAPI/slides/04a-AsyncWebAPI-CPU-bound-Compare.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/02-AsyncWebAPI/slides/04a-AsyncWebAPI-CPU-bound-Compare.PNG -------------------------------------------------------------------------------- /02-AsyncWebAPI/slides/04b-AsyncWebAPI-CPU-bound-Compare.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/02-AsyncWebAPI/slides/04b-AsyncWebAPI-CPU-bound-Compare.PNG -------------------------------------------------------------------------------- /02-AsyncWebAPI/slides/review/T01-Websurge-IO-bound-Sync.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/02-AsyncWebAPI/slides/review/T01-Websurge-IO-bound-Sync.png -------------------------------------------------------------------------------- /05-ParallelDemoDesktop/ParallelDemoDesktop/sagradafamilia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gerardo-lijs/Asynchronous-Programming-Samples/HEAD/05-ParallelDemoDesktop/ParallelDemoDesktop/sagradafamilia.png -------------------------------------------------------------------------------- /02-AsyncWebAPI/after/AsyncWebAPIDemo/AsyncWebAPIDemo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /02-AsyncWebAPI/before/AsyncWebAPIDemo/AsyncWebAPIDemo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /02-AsyncWebAPI/after/AsyncWebAPIDemo/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /02-AsyncWebAPI/before/AsyncWebAPIDemo/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /01-AsyncDesktop/after/AsyncDesktopDemo/AsyncDesktopDemo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | net5.0-windows 6 | true 7 | 8 | 9 | -------------------------------------------------------------------------------- /05-ParallelDemoDesktop/README.md: -------------------------------------------------------------------------------- 1 | # Parallel ForEach and Task.WhenAny demo application 2 | Demo soure code of a simple WPF Desktop Application to demonstrate how you can use Task Parallel Library ForEach for CPU-bound operations and how you can use Task.WhenAny for IO-bound operations 3 | 4 | -------------------------------------------------------------------------------- /01-AsyncDesktop/before/AsyncDesktopDemo/AsyncDesktopDemo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | net5.0-windows 6 | true 7 | 8 | 9 | -------------------------------------------------------------------------------- /03-AsyncProgressDesktop/README.md: -------------------------------------------------------------------------------- 1 | # Responsive Progress WPF application demo 2 | Demo source code of a WPF application to demonstrate responsive UI with a ProgressRing 3 | 4 | ## Start 5 | ![](slides/01-Start.png) 6 | 7 | ## Progress 8 | ![](slides/02-Progress.png) 9 | 10 | ## Done 11 | ![](slides/03-Done.png) 12 | -------------------------------------------------------------------------------- /04-AsyncCancelDesktop/AsyncCancelDesktop/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace AsyncCancelDesktop 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /05-ParallelDemoDesktop/ParallelDemoDesktop/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace ParallelDemoDesktop 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /01-AsyncDesktop/after/AsyncDesktopDemo/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /01-AsyncDesktop/before/AsyncDesktopDemo/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /03-AsyncProgressDesktop/AsyncProgressDesktop/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace AsyncProgressDesktop 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /01-AsyncDesktop/after/AsyncDesktopDemo/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace AsyncDesktopDemo 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /01-AsyncDesktop/before/AsyncDesktopDemo/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace AsyncDesktopDemo 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /01-AsyncDesktop/README.md: -------------------------------------------------------------------------------- 1 | # Responsive WPF application demo 2 | Demo source code of a WPF application to demonstrate responsive UI and the beneficts of using async 3 | 4 | ## Synchronous code 5 | ![](slides/01-AsyncDesktopBad.PNG) 6 | This is bad! Application is not responding 7 | 8 | ## Asynchronous code 9 | ![](slides/02-AsyncDesktopGood.PNG) 10 | This is good! Application still responsive with 100% CPU use 11 | 12 | ## Code compare 13 | ![](slides/03-CodeCompare.PNG) 14 | -------------------------------------------------------------------------------- /04-AsyncCancelDesktop/AsyncCancelDesktop/AsyncCancelDesktop.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | net5.0-windows 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /03-AsyncProgressDesktop/AsyncProgressDesktop/AsyncProgressDesktop.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | net5.0-windows 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /02-AsyncWebAPI/after/AsyncWebAPIDemo/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.Hosting; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace AsyncWebAPIDemo 11 | { 12 | public class Program 13 | { 14 | public static void Main(string[] args) 15 | { 16 | CreateHostBuilder(args).Build().Run(); 17 | } 18 | 19 | public static IHostBuilder CreateHostBuilder(string[] args) => 20 | Host.CreateDefaultBuilder(args) 21 | .ConfigureWebHostDefaults(webBuilder => 22 | { 23 | webBuilder.UseStartup(); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /02-AsyncWebAPI/before/AsyncWebAPIDemo/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.Hosting; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace AsyncWebAPIDemo 11 | { 12 | public class Program 13 | { 14 | public static void Main(string[] args) 15 | { 16 | CreateHostBuilder(args).Build().Run(); 17 | } 18 | 19 | public static IHostBuilder CreateHostBuilder(string[] args) => 20 | Host.CreateDefaultBuilder(args) 21 | .ConfigureWebHostDefaults(webBuilder => 22 | { 23 | webBuilder.UseStartup(); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /04-AsyncCancelDesktop/README.md: -------------------------------------------------------------------------------- 1 | # Cancellation in a WPF application demo 2 | Demo soure code to demonstrate the simple use of CancellationToken 3 | 4 | In this demo we need to cancel a ParallelEnumerable (TPL) so we use the .WithCancellation extensions to pass the CancellationToken 5 | 6 | ```csharp 7 | private async Task CalculatePrimeNumbersImpl() 8 | { 9 | _ctsCalculatePrimeNumbers = new CancellationTokenSource(); 10 | 11 | try 12 | { 13 | int primesCount = await Task.Run(() => 14 | ParallelEnumerable.Range(StartNumber, EndNumber).WithCancellation(_ctsCalculatePrimeNumbers.Token).Count(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0))); 15 | 16 | ResultText = $"{primesCount} prime numbers between {StartNumber} and {EndNumber}"; 17 | } 18 | catch (OperationCanceledException) 19 | { 20 | ResultText = "Cancelled"; 21 | } 22 | } 23 | ``` 24 | -------------------------------------------------------------------------------- /02-AsyncWebAPI/after/AsyncWebAPIDemo/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:60636", 8 | "sslPort": 0 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "api/cpubound?start=1&end=10000000", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "AsyncWebAPIDemo": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "api/cpubound?start=1&end=10000000", 24 | "applicationUrl": "http://localhost:5001", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /02-AsyncWebAPI/before/AsyncWebAPIDemo/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:60635", 8 | "sslPort": 0 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "api/cpubound?start=1&end=10000000", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "AsyncWebAPIDemo": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "api/cpubound?start=1&end=10000000", 24 | "applicationUrl": "http://localhost:5000", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /02-AsyncWebAPI/before/AsyncWebAPIDemo/Controllers/CPUBoundController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace AsyncWebAPIDemo.Controllers 9 | { 10 | [Route("api/[controller]")] 11 | [ApiController] 12 | public class CPUBoundController : ControllerBase 13 | { 14 | private int GetPrimesCount(int start, int count) 15 | { 16 | return ParallelEnumerable.Range(start, count).Count(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0)); 17 | } 18 | 19 | // GET api/cpubound 20 | // .\bombardier.exe "http://localhost:60635/api/cpubound?start=1&end=1000000" -n 20 -t 100s 21 | [HttpGet] 22 | public ActionResult Get([FromQuery] int start, [FromQuery] int end) 23 | { 24 | return GetPrimesCount(start, end); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /01-AsyncDesktop/after/AsyncDesktopDemo/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 1 13 | 14 | 50000000 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /01-AsyncDesktop/before/AsyncDesktopDemo/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 1 13 | 14 | 50000000 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /05-ParallelDemoDesktop/ParallelDemoDesktop/ParallelDemoDesktop.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | net5.0-windows 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | PreserveNewest 19 | 20 | 21 | PreserveNewest 22 | 23 | 24 | PreserveNewest 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /02-AsyncWebAPI/after/AsyncWebAPIDemo/Controllers/CPUBoundController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace AsyncWebAPIDemo.Controllers 9 | { 10 | [Route("api/[controller]")] 11 | [ApiController] 12 | public class CPUBoundController : ControllerBase 13 | { 14 | private Task GetPrimesCountAsync(int start, int count) 15 | { 16 | return Task.Run(() => 17 | ParallelEnumerable.Range(start, count).Count(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0))); 18 | } 19 | 20 | // GET api/cpubound 21 | // .\bombardier.exe "http://localhost:60636/api/cpubound?start=1&end=1000000" -n 20 -t 100s 22 | [HttpGet] 23 | public async Task> Get([FromQuery] int start, [FromQuery] int end) 24 | { 25 | return await GetPrimesCountAsync(start, end); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /04-AsyncCancelDesktop/AsyncCancelDesktop/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /05-ParallelDemoDesktop/ParallelDemoDesktop/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /03-AsyncProgressDesktop/AsyncProgressDesktop/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /04-AsyncCancelDesktop/AsyncCancelDesktop.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.539 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsyncCancelDesktop", "AsyncCancelDesktop\AsyncCancelDesktop.csproj", "{3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {7EE287A5-1681-4494-88D6-CC16068FC4A9} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /05-ParallelDemoDesktop/ParallelDemoDesktop.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.539 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParallelDemoDesktop", "ParallelDemoDesktop\ParallelDemoDesktop.csproj", "{3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {7EE287A5-1681-4494-88D6-CC16068FC4A9} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /02-AsyncWebAPI/after/AsyncWebAPIDemo.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.539 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsyncWebAPIDemo", "AsyncWebAPIDemo\AsyncWebAPIDemo.csproj", "{EA4AF0C1-7169-4030-9B49-A6D516AFD3FC}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {EA4AF0C1-7169-4030-9B49-A6D516AFD3FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {EA4AF0C1-7169-4030-9B49-A6D516AFD3FC}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {EA4AF0C1-7169-4030-9B49-A6D516AFD3FC}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {EA4AF0C1-7169-4030-9B49-A6D516AFD3FC}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {5608948F-1E08-4F1D-9617-C7700CDE1897} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /02-AsyncWebAPI/before/AsyncWebAPIDemo.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.539 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsyncWebAPIDemo", "AsyncWebAPIDemo\AsyncWebAPIDemo.csproj", "{EA4AF0C1-7169-4030-9B49-A6D516AFD3FC}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {EA4AF0C1-7169-4030-9B49-A6D516AFD3FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {EA4AF0C1-7169-4030-9B49-A6D516AFD3FC}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {EA4AF0C1-7169-4030-9B49-A6D516AFD3FC}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {EA4AF0C1-7169-4030-9B49-A6D516AFD3FC}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {5608948F-1E08-4F1D-9617-C7700CDE1897} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /03-AsyncProgressDesktop/AsyncProgressDesktop.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.539 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsyncProgressDesktop", "AsyncProgressDesktop\AsyncProgressDesktop.csproj", "{3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {7EE287A5-1681-4494-88D6-CC16068FC4A9} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /01-AsyncDesktop/after/AsyncDesktopDemo.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.539 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsyncDesktopDemo", "AsyncDesktopDemo\AsyncDesktopDemo.csproj", "{3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {7EE287A5-1681-4494-88D6-CC16068FC4A9} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /01-AsyncDesktop/before/AsyncDesktopDemo.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.539 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsyncDesktopDemo", "AsyncDesktopDemo\AsyncDesktopDemo.csproj", "{3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {3D40C90F-BEB6-4435-8A07-CA05CCAEEC52}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {7EE287A5-1681-4494-88D6-CC16068FC4A9} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /02-AsyncWebAPI/README.md: -------------------------------------------------------------------------------- 1 | # Scalability and performance in web applications demo 2 | Demo source code of two Web API to demonstrate performance of using async with IO-bound and CPU-bound operations 3 | 4 | # Web API running IO-bound operation 5 | 6 | ## Synchronous code 7 | ![](slides/02-AsyncWebAPI-IO-bound-CodeSync.PNG) 8 | 9 | ## Asynchronous code 10 | ![](slides/03-AsyncWebAPI-IO-bound-Code.PNG) 11 | 12 | ## Performance compare 13 | ![](slides/01-AsyncWebAPI-IO-bound-Compare.PNG) 14 | 15 | > Using async/await makes it approximately ten times better! 16 | 17 | # Web API running IO-bound operation 18 | 19 | ## Synchronous code 20 | ![](slides/05-SyncCode-CPU-bound.PNG) 21 | 22 | ## Asynchronous code 23 | ![](slides/06-AsyncCode-CPU-bound.PNG) 24 | 25 | ## Performance compare 26 | ![](slides/04a-AsyncWebAPI-CPU-bound-Compare.PNG) 27 | Synchronous CPU-bound 28 | 29 | ![](slides/04b-AsyncWebAPI-CPU-bound-Compare.PNG) 30 | Asynchronous CPU-bound 31 | 32 | > Using async/await makes it worse in this case! 33 | 34 | ## Summary 35 | 36 | * Use async with IO-bound operations whenever possible 37 | * Don’t block! 38 | * Don’t use async for expensive CPU-bound operations 39 | * Use benchmarking tools such as Bombardier (https://github.com/codesenberg/bombardier) 40 | 41 | I still need more performance, what can I do? 42 | * Scale up 43 | * Scale out whole application using Docker/Kubernetes 44 | * Scale out only expensive CPU-bound operations to Azure Functions 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Asynchronous programming in .NET samples 2 | 3 | * [Responsive WPF application demo](01-AsyncDesktop) 4 | Demo source code of a WPF application to demonstrate responsive UI and the beneficts of using async 5 | * [Scalability and performance in web applications demo](02-AsyncWebAPI) 6 | Demo source code of two Web API to demonstrate performance of using async with IO-bound and CPU-bound operations 7 | * [Progress in a WPF application demo](03-AsyncProgressDesktop) 8 | Demo soure code to demonstrate the simple use of a ProgressRing 9 | * [Cancellation in a WPF application demo](04-AsyncCancelDesktop) 10 | Demo soure code to demonstrate the simple use of CancellationToken 11 | * [Parallel ForEach and Task.WhenAny demo application](05-ParallelDemoDesktop) 12 | Demo soure code of a simple WPF Desktop Application to demonstrate how you can use Task Parallel Library ForEach for CPU-bound operations and how you can use Task.WhenAny for IO-bound operations 13 | 14 | ## Notes 15 | * In WPF desktop sample I didn't use MVVM to have a minimalistic example 16 | * In Progress, Cancellation and Parallel samples source code I used [ReactiveUI](https://reactiveui.net/) as MVVM framework, [MahApps](https://mahapps.com/) and [OpenCVSharp](https://github.com/shimat/opencvsharp) for simulating a CPU-bound expensive operation. If you are interested in this projects it's worth checkin it out since they are a minimalistic example and easy to see how they work. 17 | -------------------------------------------------------------------------------- /01-AsyncDesktop/before/AsyncDesktopDemo/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace AsyncDesktopDemo 17 | { 18 | /// 19 | /// Interaction logic for MainWindow.xaml 20 | /// 21 | public partial class MainWindow : Window 22 | { 23 | public MainWindow() 24 | { 25 | InitializeComponent(); 26 | } 27 | 28 | private void Button_Click(object sender, RoutedEventArgs e) 29 | { 30 | int.TryParse(StartNumberTextBox.Text, out int start); 31 | int.TryParse(EndNumberTextBox.Text, out int end); 32 | if (start == 0 || end == 0) return; 33 | 34 | ResultTextBlock.Text = ""; 35 | int result = GetPrimesCount(start, end); 36 | ResultTextBlock.Text = $"{result} prime numbers between {start} and {end}"; 37 | } 38 | 39 | private int GetPrimesCount(int start, int count) 40 | { 41 | return ParallelEnumerable.Range(start, count).Count(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0)); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /03-AsyncProgressDesktop/AsyncProgressDesktop/Views/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |