#DevUgZg, Zagreb 2019-11-27
http://bit.ly/DevUgZg-async-await
Vedran Mandić, MCSD, MCSA, MCT
30min + 30min (very fast tempo)
System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> System.InvalidOperationException: Operation is not valid due to the current state of the object. at ConsoleApplication6.Program.Main(String[] args) in C:\Projects\ConsoleApplication6\ConsoleApplication6\Program.cs:line 29 --- End of inner exception stack trace --- at ConsoleApplication6.Program.Main(String[] args) in C:\Projects\ConsoleApplication6\ConsoleApplication6\Program.cs:line 39 --- End of inner exception stack trace --- at ConsoleApplication6.Program.Main(String[] args) in C:\Projects\ConsoleApplication6\ConsoleApplication6\Program.cs:line 51 ---> (Inner Exception #0) System.AggregateException: One or more errors occurred. ---> System.InvalidOperationException: Operation is not valid due to the current state of the object. at ConsoleApplication6.Program.Main(String[] args) in C:\Projects\ConsoleApplication6\ConsoleApplication6\Program.cs:line 29 --- End of inner exception stack trace --- at ConsoleApplication6.Program.Main(String[] args) in C:\Projects\ConsoleApplication6\ConsoleApplication6\Program.cs:line 39 ---> (Inner Exception #0) System.InvalidOperationException: Operation is not valid due to the current state of the object. at ConsoleApplication6.Program.Main(String[] args) in C:\Projects\ConsoleApplication6\ConsoleApplication6\Program.cs:line 29<--- ---> (Inner Exception #1) System.FormatException: One of the identified items was in an invalid format. at ConsoleApplication6.Program.Main(String[] args) in C:\Projects\ConsoleApplication6\ConsoleApplication6\Program.cs:line 35<--- <--- ---> (Inner Exception #1) System.NotImplementedException: The method or operation is not implemented. at ConsoleApplication6.Program.Main(String[] args) in C:\Projects\ConsoleApplication6\ConsoleApplication6\Program.cs:line 47<--- System.AggregateException: One or more errors occurred. ---> System.NotImplementedException: The method or operation is not implemented. at ConsoleApplication6.Program.Main(String[] args) in C:\Projects\ConsoleApplication6\ConsoleApplication6\Program.cs:line 47 --- End of inner exception stack trace --- ---> (Inner Exception #0) System.NotImplementedException: The method or operation is not implemented. at ConsoleApplication6.Program.Main(String[] args) in C:\Projects\ConsoleApplication6\ConsoleApplication6\Program.cs:line 47<--- ---> (Inner Exception #1) System.InvalidOperationException: Operation is not valid due to the current state of the object. at ConsoleApplication6.Program.Main(String[] args) in C:\Projects\ConsoleApplication6\ConsoleApplication6\Program.cs:line 29<--- ---> (Inner Exception #2) System.FormatException: One of the identified items was in an invalid format. at ConsoleApplication6.Program.Main(String[] args) in C:\Projects\ConsoleApplication6\ConsoleApplication6\Program.cs:line 35<---
async void: I wish we could have not allowed that...
- Mads Torgersen [MSFT], Oct 24 2019
You can take a sip of 🍺 now...
thread 1
thread 42
thread 3
thread 114
thread 3
thread 1
TIP: Understand the need for SyncContext by S. Cleary,
MSDN Feb 2011
Task.Run(() => lblInfo.Text = "Boom!");
use async / await (all the way) if unsure or must have
no need for overengineering with Parallel or Threads
public async Task<string> GetUniqueUsernameAsync(int id)
{
var user = await db.Users.SingleOrDefaultAsync(x => x.Id == id);
return user?.Username ?? throw new UserNotFoundException(id);
}
please meassure perf!
async / await is not always good!
but... e.g. do apply it on a highly requested web endpoint
public string GetUniqueUsername(int id)
{
var user = db.Users.SingleOrDefault(x => x.Id == id);
return user?.Username ?? throw new UserNotFoundException(id);
}
avoid if possible dangerous "sync over async" blocking
good luck catching that exception or awaitng the method
public Task<string> GetUniqueUsername(int id)
{
// DON'T DO THIS, PLEASE... JUST DON'T
var user = db.Users.SingleOrDefaultAsync(x => x.Id == id).Result;
return Task.FromResult(user?.Username
?? throw new UserNotFoundException(id));
}
if you must do "sync over async"...
...then at least you'll get a proper exception
public string GetUniqueUsername(int id)
{
var user = db.Users.SingleOrDefaultAsync(x => x.Id == id)
.GetAwaiter()
.GetResult();
return user?.Username ?? throw new UserNotFoundException(id);
}
thanks you can leave now for pizza :)
https://michaelscodingspot.com/2019/01/17/c-deadlocks-in-depth-part-1/
https://michaelscodingspot.com/2019/01/24/c-deadlocks-in-depth-part-2/
Locking and Deadlocks explained by example with async / await
https://odetocode.com/blogs/scott/archive/2019/03/04/await-the-async-letdown.asp
thoughts by a senior C# developer and author on why working with async / await is hard and prone to errors
an excellent summary of multiple how-to and don’ts with async / await in dotnet core
https://dev.to/stuartblang/miscellaneous-c-async-tips-3o47
how to deal with lazy initialization in CTOR that has to become async (AsyncLazy example)
http://blog.i3arnon.com/2015/07/02/task-run-long-running/
TaskCreationOptions.LongRunning explained, one can read that an actual thread (not from the thread pool) is created
http://blog.stephencleary.com/2017/03/aspnetcore-synchronization-context.html - SyncContext in ASP.NET Core and dangers one can face
https://msdn.microsoft.com/en-us/magazine/dn802603.aspx
a detailed overview how async applies to the ASP.NET runtime, how thread-pool allocates threads and when does context switching happen
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
the evergreen example of why not to block async calls with .Result or .Wait() in traditional environments which have a dedicated syncContext
https://msdn.microsoft.com/en-us/magazine/gg598924.aspx
why we need the synchronization context
https://markheath.net/post/async-antipatterns
a summary of all the examples and more, fresh 2019 article
https://www.youtube.com/watch?v=av5YNd4X3dY
correcting Common Mistakes When Using Async/Await in .NET - Brandon Minnick
https://www.youtube.com/watch?v=Al8LrBKpZEU
Back to Basics: Efficient Async and Await - Filip Ekberg
https://dev.to/hardkoded/a-fairy-tale-about-async-voids-events-and-error-handling-1afi
real world example of async void impact
https://www.youtube.com/watch?v=-cJjnVTJ5og
“Why your ASP.NET Core application won’t scale?”, has a lot of cool async trap examples at the end - D. Edwards and D. Fowler at NDC London 2019
https://www.youtube.com/watch?v=ghDS4_NFbcQ
“The promise of an async future awaits” - overview of async and await and it’s issues, Bill Wagner (.NET docs team) at NDC London 2019, explaining Sync, Async and Parallel with making an English breakfast example.
https://www.youtube.com/watch?v=XpgN7y_EXps
“Async & Await (You’re doing it wrong)”, good examples of bad usage: async void, async void lambda, async constructor and property, running async in sync (blocking examples)
https://chrisstclair.co.uk/demystifying-async-await
a quick and simple example of how bad application blocks the UI and how to quickly fix it.
https://medium.com/rubrikkgroup/understanding-async-avoiding-deadlocks-e41f8f2c6f5d
when and how can a deadlock occur with async / await, a table view breakdown depending in which execution context the task is run, excellent overview
https://olitee.com/2015/01/c-async-await-common-deadlock-scenario/
a deadlock scenario explained
https://devblogs.microsoft.com/pfxteam/asyncawait-faq/
probably the best and concrete FAQ on async / await there is on the internet
https://devblogs.microsoft.com/pfxteam/await-and-ui-and-deadlocks-oh-my/
the most simple and right explanation of deadlock common scenario when the UI thread is blocked due to .Result or Wait() and can not restore new state from the updated SynchronizationContext (i.e. windows message loop when working with Windows Forms and WPF).
VEDRAN MANDIĆ
mandic.vedran@gmail.com
@vekzdran @vmandic
http://bit.ly/DevUgZg-async-await