-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathSyncOverAsyncExtensions.cs
41 lines (35 loc) · 1.72 KB
/
SyncOverAsyncExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
static class SyncOverAsyncExtensions
{
static LimitedConcurrencyLevelTaskScheduler scheduler = new LimitedConcurrencyLevelTaskScheduler(1);
public static void Explain(this SyncOverAsync runnable, TextWriter writer)
{
writer.WriteLine(@"
- `Task.Result` or `Task.Wait` on asynchronous operations is much worse than calling truly synchronous APIs. Here is what happens
- An asynchronous operation is kicked off.
- The calling thread is blocked waiting for that operation to complete.
When the asynchronous operation completes, it unblocks the code waiting on that operation. This takes place on another thread.
- This leads to thread-pool starvation and service outages due to 2 threads being used instead of 1 to complete synchronous operations.
- If a synchronization context is available it can even lead to deadlocks
");
}
public static Task WrapInContext(this SyncOverAsync runnable, Action action)
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine($"Entering SyncContext {Thread.CurrentThread.ManagedThreadId}");
action();
Console.WriteLine($"Exiting SyncContext {Thread.CurrentThread.ManagedThreadId}");
}, CancellationToken.None, TaskCreationOptions.None, scheduler);
}
public static async Task<string> DoAsyncOperation(this SyncOverAsync runnable)
{
Console.WriteLine($"Entering DoAsyncOperation {Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(2);
Console.WriteLine($"Finishing DoAsyncOperation {Thread.CurrentThread.ManagedThreadId}");
return "Hello";
}
}