SlideShare a Scribd company logo
BEHIND MODERN
CONCURRENCY PRIMITIVES
INTRODUCTION
Bartosz Sypytkowski
▪ @Horusiath
▪ b.sypytkowski@gmail.com
▪ bartoszsypytkowski.com
 Concurrency in user vs. kernel space
 Thread pools
 Schedulers
 Coroutines
 State machines
AGENDA
WHY DO WE USE THIS?
ASYNC/AWAIT
Task.Run(async () =>
{
await using var conn = new SqlConnection(ConnectionString);
await conn.OpenAsync();
var user = await conn.QueryFirstAsync<User>(
"SELECT * FROM Users WHERE Id = @id",
new { id = 100 });
Console.WriteLine($"Received user {user.FirstName} {user.LastName}");
});
INSTEAD OF THIS?
THREAD API
new Thread(() =>
{
var conn = new SqlConnection(ConnectionString);
conn.Open();
var user = conn.QueryFirst<User>(
"SELECT * FROM Users WHERE Id = @id",
new { id = 100 });
Console.WriteLine($"Received user {user.FirstName} {user.LastName}");
}).Start();
Thread Pool*
Managed
Thread
Managed
Thread
OS
Thread
THREADS TASKS
User space
Kernel space
User space
Kernel space
Managed
Thread
OS
Thread
OS
Thread
Scheduler
OS
Thread
OS
Thread
OS
Thread
Task Task Task Task Task Task
Task Task Task Task Task Task
Task Task Task Task Task Task
THREAD POOLS
THREAD
POOL
BASICS
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Job Queue
PINNING THREAD TO CPU
var threads = Process.GetCurrentProcess().Threads;
var cpuCount = Environment.ProcessorCount;
Console.WriteLine($"Using {threads.Count} threads on {cpuCount} cores.");
// => Using 10 threads on 4 cores.
for (int i = 0; i < threads.Count; i++)
{
var pthread = threads[i];
var cpuMask = (1L << (i % cpuCount));
pthread.IdealProcessor = i % cpuCount; // set preferred thread(s)
pthread.ProcessorAffinity = (IntPtr)cpuMask; // set thread affinity mask
}
NOTE: it’s not always possible (iOS) or respected.
SHARING DATA IN MULTI-CPU ARCHITECTURE
HARDWARE
ARCHITECTURE
101 CPU 1
L1 cache
L1 cache
L3 cache
CPU 2
L1 cache
L1 cache
RAM
CPU L1 cache: 1ns
CPU L2 cache: 4-7ns
CPU L2 cache: 100ns
HARDWARE
ARCHITECTURE
NUMA CPU 1
CPU 2
L1-2
cache
CPU 3
CPU 4
L1-2
cache
CPU 5
CPU 6
L1-2
cache
CPU 7
CPU 8
L1-2
cache
THREAD
POOL
MULTIPLE
QUEUES
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
THREAD
POOL
WORK STEALING
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Job
Job Job Job
Job
Job
Job Job Job Job
THREAD
POOL
WORK STEALING
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Job
Job Job Job
Job
Job
? Job Job Job
Empty
Queue
THREAD
POOL
WORK STEALING
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Job
Job Job Job
Job
Job
? Job Job Job
THREAD
POOL
WORK STEALING
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Job Job Job
Job
Job
Job Job Job
Job
COMPAR
ING
VECTOR
CLOCKS
AFFINITY
BASED
THREAD POOL
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
S1
S1
S1
S1
S2
S2
S3
S2
S3
S3
S4
S5
S4
S4
S5
Always map entity to the same thread / core
AFFINITY THREAD POOL: PERFORMANCE
Source: https://scalac.io/improving-akka-dispatchers/
THREAD-PER-CORE
ARCHITECTURE
WORKING WITH I/O
SCENARIO #1
READING A FILE
WHY IS THIS
CODE BAD?
static async Task ProcessFiles(FileInfo[] files)
{
var tasks = new Task[files.Length];
for (int i = 0; i < files.Length; i++)
tasks[i] = ProcessFile(files[i]);
await Task.WhenAll(tasks);
}
static async Task ProcessFile(FileInfo file)
{
using var stream = file.OpenRead();
using var reader = new StreamReader(stream);
var text = reader.ReadToEnd();
Process(text);
}
WHY IS THIS
CODE BAD?
static async Task ProcessFiles(FileInfo[] files)
{
var tasks = new Task[files.Length];
for (int i = 0; i < files.Length; i++)
tasks[i] = ProcessFile(files[i]);
await Task.WhenAll(tasks);
}
static async Task ProcessFile(FileInfo file)
{
using var stream = file.OpenRead();
using var reader = new StreamReader(stream);
var text = reader.ReadToEnd();
Process(text);
}
Blocking the thread belonging
to a thread pool shared with
other tasks.
I/O
1. Just use async I/O API…
WHAT CAN WE DO
ABOUT IT?
I/O
1. Just use async I/O API…
2. … but what when it’s not possible?
WHAT CAN WE DO
ABOUT IT?
I/O
1. Just use async I/O API…
2. … but what when it’s not possible?
WHAT CAN WE DO
ABOUT IT?
internal static class LmdbMethods
{
[DllImport("lmdb", CallingConvention = CallingConvention.Cdecl)]
public static extern int mdb_dbi_open(IntPtr txn, string name, DatabaseOpenFlags flags, out uint db);
[DllImport("lmdb", CallingConvention = CallingConvention.Cdecl)]
public static extern int mdb_cursor_get(IntPtr cursor, ref ValueStructure key, ref ValueStructure
data, CursorOperation op);
[DllImport("lmdb", CallingConvention = CallingConvention.Cdecl)]
public static extern int mdb_cursor_put(IntPtr cursor, ref ValueStructure key, ref ValueStructure
value, CursorPutOptions flags);
// other methods
}
THREAD
POOL
I/O THREADS
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Managed
Thread
I/O
Threads
Managed
Thread
Managed
Thread
THREAD
POOL
I/O THREADS
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Managed
Thread
I/O
Threads
Managed
Thread
Managed
Thread
J1
THREAD
POOL
I/O THREADS
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Managed
Thread
I/O
Threads
Managed
Thread
Managed
Thread
J1
THREAD
POOL
I/O THREADS
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Managed
Thread
I/O
Threads
Managed
Thread
Managed
Thread
J1
THREAD
POOL
I/O THREADS
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Managed
Thread
I/O
Threads
Managed
Thread
Managed
Thread
J2
GOROUTINES & I/O
DEALING WITH KERNEL CALLS
COMPAR
ING
VECTOR
CLOCKS
GOROUTINES
I/O CALLS
CPU 1
Agent
Runtime
Thread
CPU 2
Agent
Runtime
Thread
CPU 3
Agent
Runtime
Thread
CPU 4
Agent
Runtime
Thread
COMPAR
ING
VECTOR
CLOCKS
GOROUTINES
I/O CALLS
CPU 1
Agent
Runtime
Thread
CPU 2
Agent
Runtime
Thread
CPU 3
Agent
Runtime
Thread
CPU 4
Agent
Runtime
Thread
sys
call
COMPAR
ING
VECTOR
CLOCKS
GOROUTINES
I/O CALLS
CPU 1
Agent
CPU 2
Agent
Runtime
Thread
CPU 3
Agent
Runtime
Thread
CPU 4
Agent
Runtime
Thread
Runtime
Thread
sys
call
COMPAR
ING
VECTOR
CLOCKS
GOROUTINES
I/O CALLS
CPU 1
Agent
CPU 2
Agent
Runtime
Thread
CPU 3
Agent
Runtime
Thread
CPU 4
Agent
Runtime
Thread
Runtime
Thread
sys
call
Runtime
Thread
SCHEDULERS
Preemptive vs. Cooperative
Scheduler depends on coroutines
to return control to scheduler.
PREEMPTIVE
Scheduler is in charge of
execution. Coroutines can be
preempted.
COOPERATIVE
SCENARIO #2
CREATE AN EXCEL FILE
COMPAR
ING
VECTOR
CLOCKS
BUILDING
AN EXCEL
FILE
app.get('/valuations.xlsx', async (req, res) => {
var workbook = new Excel.Workbook();
var worksheet = workbook.addWorksheet("Valuations");
var valuations = await getValuations(req.params.id);
for (let valuation in valuations) {
worksheet.addRow(valuation);
}
await workbook.xlsx.write(res);
});
COMPAR
ING
VECTOR
CLOCKS
BUILDING
AN EXCEL
FILE
app.get('/valuations.xlsx', async (req, res) => {
var workbook = new Excel.Workbook();
var worksheet = workbook.addWorksheet("Valuations");
var valuations = await getValuations(req.params.id);
for (let valuation in valuations) {
worksheet.addRow(valuation); // 500μs
}
await workbook.xlsx.write(res);
});
COMPAR
ING
VECTOR
CLOCKS
BUILDING
AN EXCEL
FILE
app.get('/valuations.xlsx', async (req, res) => {
var workbook = new Excel.Workbook();
var worksheet = workbook.addWorksheet("Valuations");
var valuations = await getValuations(req.params.id);
for (let valuation in valuations) { // 20,000 items
worksheet.addRow(valuation); // 500μs
}
await workbook.xlsx.write(res);
});
COMPAR
ING
VECTOR
CLOCKS
BUILDING
AN EXCEL
FILE
app.get('/valuations.xlsx', async (req, res) => {
var workbook = new Excel.Workbook();
var worksheet = workbook.addWorksheet("Valuations");
var valuations = await getValuations(req.params.id);
for (let valuation in valuations) { // 20,000 items
worksheet.addRow(valuation); // 500μs
}
await workbook.xlsx.write(res);
});
Total loop execution time: 10 seconds
HOW TO DEAL WITH LONG RUNNING TASKS?
LONG
RUNNING
TASK
SEPARATE
THREAD
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Scheduler
LONG
RUNNING
TASK
SEPARATE
THREAD
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Scheduler
Task
Task.Factory.StartNew(DownloadExcel, TaskCreationOptions.LongRunning)
LONG
RUNNING
TASK
SEPARATE
THREAD
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Scheduler
Task
Task.Factory.StartNew(DownloadExcel, TaskCreationOptions.LongRunning)
Managed
Thread
LONG
RUNNING
TASK
SEPARATE
THREAD
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Scheduler
Managed
Thread
Task
LONG
RUNNING
TASK
SEPARATE
THREAD
CPU 1
Agent
Managed
Thread
CPU 2
Agent
Managed
Thread
CPU 3
Agent
Managed
Thread
CPU 4
Agent
Managed
Thread
Scheduler
Managed
Thread
Task
COMPAR
ING
VECTOR
CLOCKS
INTRODUCING
INTERRUPTION
POINTS
function park() {
return new Promise((resolve) => setTimeout(resolve, 0));
}
app.get('/valuations.xlsx', async (req, res) => {
var workbook = new Excel.Workbook();
var worksheet = workbook.addWorksheet("Valuations");
var valuations = await getValuations(req.params.id);
var i = 0;
for (let valuation in valuations) { // 20,000 items
if ((i++) % 100 === 0) {
await park();
}
worksheet.addRow(valuation); // 500μs
}
await workbook.xlsx.write(res);
});
PREEMPTIVE SCHEDULER
step-based / time-based
STEP-BASED PREEMPTION
% hello world program
-module(helloworld).
-export([start/0, write/1]).
write([]) -> ok;
write([File|T]) ->
io:fwrite("Writing a file ~p~n", File),
write(T).
start() ->
Files = ["A", "B", "C"],
write(Files).
STEP-BASED PREEMPTION
Reduction counter under the hood
% hello world program
-module(helloworld).
-export([start/0, write/1]).
write([], Reductions) -> ok;
write([File|T], Reductions) ->
% if Reductions == 0 then yield()
io:fwrite("Writing a file ~p~n", File),
write(T, Reductions-1).
start() ->
Files = ["A", "B", "C"],
write(Files, 2000).
• JavaScript promises
• .NET Task Parallel Library
• Java/Scala Futures
PREEMPTIVE
• OS threads
• Go goroutines
• Erlang processes
COOPERATIVE
COROUTINES
eager vs. lazy
let run () = async {
let sw = Stopwatch()
sw.Start()
let t1 = Async.Sleep(5000)
let t2 = Async.Sleep(5000)
do! t1
do! t2
printfn "Time passed: %ims" sw.ElapsedMilliseconds
}
static async Task Run()
{
var sw = new Stopwatch();
sw.Start();
var t1 = Task.Delay(TimeSpan.FromSeconds(5));
var t2 = Task.Delay(TimeSpan.FromSeconds(5));
await t1;
await t2;
Console.WriteLine(
$"Time passed: {sw.ElapsedMilliseconds}ms");
}
let run () = async {
let sw = Stopwatch()
sw.Start()
let t1 = Async.Sleep(5000)
let t2 = Async.Sleep(5000)
do! t1
do! t2
printfn "Time passed: %ims" sw.ElapsedMilliseconds
}
static async Task Run()
{
var sw = new Stopwatch();
sw.Start();
var t1 = Task.Delay(TimeSpan.FromSeconds(5));
var t2 = Task.Delay(TimeSpan.FromSeconds(5));
await t1;
await t2;
Console.WriteLine(
$"Time passed: {sw.ElapsedMilliseconds}ms");
}
5 seconds 10 seconds
let run () = async {
let sw = Stopwatch()
sw.Start()
let t1 = Async.Sleep(5000)
let t2 = Async.Sleep(5000)
do! t1
do! t2
printfn "Time passed: %ims" sw.ElapsedMilliseconds
}
static async Task Run()
{
var sw = new Stopwatch();
sw.Start();
var t1 = Task.Delay(TimeSpan.FromSeconds(5));
var t2 = Task.Delay(TimeSpan.FromSeconds(5));
await t1;
await t2;
Console.WriteLine(
$"Time passed: {sw.ElapsedMilliseconds}ms");
}
EAGER LAZY
5 seconds 10 seconds
COROUTINES
stackless vs. stackful
COMPAR
ING
VECTOR
CLOCKS
STACKLESS
COROUTINES
OLD CALLBACK API
app.get('/valuations.xlsx', function (req, res, next) {
var workbook = new Excel.Workbook();
var worksheet = workbook.addWorksheet("Valuations");
getValuations(req.params.id, function (err, valuations) {
for (let valuation in valuations) {
worksheet.addRow(valuation);
}
workbook.xlsx.write(res, function (err) {
next();
});
});
});
COMPAR
ING
VECTOR
CLOCKS
STACKLESS
COROUTINES
app.get('/valuations.xlsx', (req, res) => {
var workbook = new Excel.Workbook();
var worksheet = workbook.addWorksheet("Valuations");
return getValuations(req.params.id)
.then((valuations) => {
for (let valuation in valuations) {
worksheet.addRow(valuation);
}
return workbook.xlsx.write(res);
});
});
OLD PROMISE API
COMPAR
ING
VECTOR
CLOCKS
STACKLESS
COROUTINES
app.get('/valuations.xlsx', async (req, res) => {
var workbook = new Excel.Workbook();
var worksheet = workbook.addWorksheet("Valuations");
var valuations = await getValuations(req.params.id);
for (let valuation in valuations) {
worksheet.addRow(valuation);
}
await workbook.xlsx.write(res);
});
PROBLEM OF FUNCTION COLOURING
STACKFUL
COROUTINES
STACK
main activation
frame
function foo(a, b)
print("foo", a)
bar("foo", b)
end
function bar(caller, x)
print(“bar: ", caller)
coroutine.yield()
print(“bar", x)
end
co = coroutine.create(foo)
coroutine.resume(co, 1, 2)
print(“main”)
coroutine.resume(co)
STACKFUL
COROUTINES
STACK
main activation
frame
function foo(a, b)
print("foo", a)
bar("foo", b)
end
function bar(caller, x)
print(“bar: ", caller)
coroutine.yield()
print(“bar", x)
end
co = coroutine.create(foo)
coroutine.resume(co, 1, 2)
print(“main”)
coroutine.resume(co)
foo activation
frame
Start of
coroutine
stack
STACKFUL
COROUTINES
STACK
main activation
frame
function foo(a, b)
print("foo", a)
bar("foo", b)
end
function bar(caller, x)
print(“bar: ", caller)
coroutine.yield()
print(“bar", x)
end
co = coroutine.create(foo)
coroutine.resume(co, 1, 2)
print(“main”)
coroutine.resume(co)
foo activation
frame
print activation
frame
STACKFUL
COROUTINES
STACK
main activation
frame
function foo(a, b)
print("foo", a)
bar("foo", b)
end
function bar(caller, x)
print(“bar: ", caller)
coroutine.yield()
print(“bar", x)
end
co = coroutine.create(foo)
coroutine.resume(co, 1, 2)
print(“main”)
coroutine.resume(co)
foo activation
frame
bar activation
frame
STACKFUL
COROUTINES
STACK
main activation
frame
function foo(a, b)
print("foo", a)
bar("foo", b)
end
function bar(caller, x)
print(“bar: ", caller)
coroutine.yield()
print(“bar", x)
end
co = coroutine.create(foo)
coroutine.resume(co, 1, 2)
print(“main”)
coroutine.resume(co)
foo activation
frame
bar activation
frame
print activation
frame
STACKFUL
COROUTINES
STACK
main activation
frame
function foo(a, b)
print("foo", a)
bar("foo", b)
end
function bar(caller, x)
print(“bar: ", caller)
coroutine.yield()
print(“bar", x)
end
co = coroutine.create(foo)
coroutine.resume(co, 1, 2)
print(“main”)
coroutine.resume(co)
foo activation
frame
bar activation
frame
Park
coroutine
stack
STACKFUL
COROUTINES
STACK
main activation
frame
function foo(a, b)
print("foo", a)
bar("foo", b)
end
function bar(caller, x)
print(“bar: ", caller)
coroutine.yield()
print(“bar", x)
end
co = coroutine.create(foo)
coroutine.resume(co, 1, 2)
print(“main”)
coroutine.resume(co)
foo activation
frame
bar activation
frame
Park
coroutine
stack
STACKFUL
COROUTINES
STACK
main activation
frame
function foo(a, b)
print("foo", a)
bar("foo", b)
end
function bar(caller, x)
print(“bar: ", caller)
coroutine.yield()
print(“bar", x)
end
co = coroutine.create(foo)
coroutine.resume(co, 1, 2)
print(“main”)
coroutine.resume(co)
foo activation
frame
bar activation
frame
STACKFUL
COROUTINES
STACK
main activation
frame
function foo(a, b)
print("foo", a)
bar("foo", b)
end
function bar(caller, x)
print(“bar: ", caller)
coroutine.yield()
print(“bar", x)
end
co = coroutine.create(foo)
coroutine.resume(co, 1, 2)
print(“main”)
coroutine.resume(co)
foo activation
frame
bar activation
frame
print activation
frame
STACKFUL
COROUTINES
STACK
main activation
frame
function foo(a, b)
print("foo", a)
bar("foo", b)
end
function bar(caller, x)
print(“bar: ", caller)
coroutine.yield()
print(“bar", x)
end
co = coroutine.create(foo)
coroutine.resume(co, 1, 2)
print(“main”)
coroutine.resume(co)
foo activation
frame
bar activation
frame
Resume
coroutine
stack
STACKFUL
COROUTINES
STACK
main activation
frame
function foo(a, b)
print("foo", a)
bar("foo", b)
end
function bar(caller, x)
print(“bar: ", caller)
coroutine.yield()
print(“bar", x)
end
co = coroutine.create(foo)
coroutine.resume(co, 1, 2)
print(“main”)
coroutine.resume(co)
foo activation
frame
bar activation
frame
STACKFUL
COROUTINES
STACK
main activation
frame
function foo(a, b)
print("foo", a)
bar("foo", b)
end
function bar(caller, x)
print(“bar: ", caller)
coroutine.yield()
print(“bar", x)
end
co = coroutine.create(foo)
coroutine.resume(co, 1, 2)
print(“main”)
coroutine.resume(co)
foo activation
frame
bar activation
frame
print activation
frame
WHAT IS THE CORRECT STACK SIZE FOR EACH
COROUTINE?
• JavaScript promises
• .NET Task Parallel Library
• Java/Scala Futures
STACKFUL
• Go goroutines
• LUA coroutines
• (soon) Java Loom project
STACKLESS
STACKLESS COROUTINES AND
YIELD GENERATORS
ASYNC/AWAIT UNITY COROUTINES
IEnumerable WaitAndPrint()
{
print("Starting at " + Time.time);
yield return new WaitForSeconds(0.1f);
print("Ending at " + Time.time);
}
async Task WaitAndPrint()
{
Console.WriteLine("Starting at " + DateTime.Now);
await Task.Delay(100);
Console.WriteLine("Ending at " + DateTime.Now);
}
INTEGRATING TPL AND LINQ
public static class TaskExtensions
{
public static Task<T3> SelectMany<T1, T2, T3>(
this Task<T1> task,
Func<T1, Task<T2>> binding,
Func<T1, T2, T3> combine)
{
var tcs = new TaskCompletionSource<T3>();
task.ContinueWith(t1 =>
{
if (t1.IsFaulted) tcs.SetException(t1.Exception);
else if (t1.IsCanceled) tcs.SetCanceled();
else binding(t1.Result).ContinueWith(t2 =>
{
if (t2.IsFaulted) tcs.SetException(t2.Exception);
else if (t2.IsCanceled) tcs.SetCanceled();
else tcs.SetResult(combine(t1.Result, t2.Result));
});
});
return tcs.Task;
}
}
public static Task Rename(int userId, string name)
{
return from user in GetUser(userId)
from _ in SaveUser(user with { Name = name })
select 0;
}
BEHIND ASYNC/AWAIT
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
WHAT YOU SEE WHAT YOU DON’T SEE
static class Program {
static async Task Foo(int a, int b) {
Console.WriteLine("Foo", a);
await Task.Yield();
Console.WriteLine("Foo", b);
}
}
struct Foo__0 : IStateMachine {
AsyncTaskMethodBuilder builder;
int state;
int a;
int b;
public void MoveNext() {
switch (this.state) {
case -1:
Console.WriteLine("Foo", this.a);
var awaiter = Taks.Yield().GetAwaiter();
this.state = 0;
this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
// ^ awaiter.OnComplete(() =>
// ThreadPool.QueueUserWorkItem(this.MoveNext));
return;
case 0:
Console.WriteLine("Foo", this.b);
builder.SetResult();
return;
}
}
}
static class Program {
static Task Foo(int a, int b) {
var builder = AsyncTaskMethodBuilder.Create();
var stateMachine = new Foo__0();
// initialize state machine fields
stateMachine.a = a;
stateMachine.b = b;
stateMachine.state = -1;
stateMachine.builder = builder;
builder.Start(ref stateMachine);
// ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext);
return builder.Task;
}
}
AWAITER PATTERN
Custom awaitable objects
public readonly struct PromiseAwaiter<T> : INotifyCompletion
{
private readonly Promise<T> promise;
public PromiseAwaiter(Promise<T> promise)
{
this.promise = promise;
}
#region mandatory awaiter methods
public bool IsCompleted => promise.IsCompleted;
public T GetResult() => promise.Result;
public void OnCompleted(Action continuation) => promise.RegisterContinuation(continuation);
#endregion
}
ASYNC METHOD BUILDER
Custom async methods
public struct PromiseAsyncMethodBuilder<T>
{
private Promise<T>? promise;
#region mandatory methods for async state machine builder
public static PromiseAsyncMethodBuilder<T> Create() => default;
public Promise<T> Task => promise ??= new Promise<T>();
public void SetException(Exception e) => Task.TrySetException(e);
public void SetResult(T result) => Task.TrySetResult(result);
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine { }
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine { }
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { }
public void SetStateMachine(IAsyncStateMachine stateMachine) { }
#endregion
}
COST OF ASYNC
SUMMARY
 Custom AsyncMethodBuilder “docs”: https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md
 Building custom (affine) thread pool: https://bartoszsypytkowski.com/thread-safety-with-affine-thread-pools/
 What color is your function?: https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/
 How Go scheduler works: https://www.youtube.com/watch?v=-K11rY57K7k
 Thread per core architecture: https://www.datadoghq.com/blog/engineering/introducing-glommio/
REFERENCES
THANK YOU

More Related Content

What's hot

Reactive Java (33rd Degree)
Reactive Java (33rd Degree)Reactive Java (33rd Degree)
Reactive Java (33rd Degree)
Tomasz Kowalczewski
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
Piotr Pelczar
 
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListenerNode.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Islam Sharabash
 
bluespec talk
bluespec talkbluespec talk
bluespec talk
Suman Karumuri
 
Avoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promisesAvoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promises
Ankit Agarwal
 
Programming with ZooKeeper - A basic tutorial
Programming with ZooKeeper - A basic tutorialProgramming with ZooKeeper - A basic tutorial
Programming with ZooKeeper - A basic tutorial
Jeff Smith
 
Counter Wars (JEEConf 2016)
Counter Wars (JEEConf 2016)Counter Wars (JEEConf 2016)
Counter Wars (JEEConf 2016)
Alexey Fyodorov
 
Understanding greenlet
Understanding greenletUnderstanding greenlet
Understanding greenlet
Saúl Ibarra Corretgé
 
Non Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJavaNon Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJava
Frank Lyaruu
 
Callbacks, promises, generators - asynchronous javascript
Callbacks, promises, generators - asynchronous javascriptCallbacks, promises, generators - asynchronous javascript
Callbacks, promises, generators - asynchronous javascript
Łukasz Kużyński
 
Event loop
Event loopEvent loop
Event loop
codepitbull
 
Reactive programming with RxJava
Reactive programming with RxJavaReactive programming with RxJava
Reactive programming with RxJava
Jobaer Chowdhury
 
Asynchronní programování
Asynchronní programováníAsynchronní programování
Asynchronní programování
PeckaDesign.cz
 
How to send gzipped requests with boto3
How to send gzipped requests with boto3How to send gzipped requests with boto3
How to send gzipped requests with boto3
Luciano Mammino
 
Reactive programming with RxAndroid
Reactive programming with RxAndroidReactive programming with RxAndroid
Reactive programming with RxAndroid
Savvycom Savvycom
 
Concurrency Concepts in Java
Concurrency Concepts in JavaConcurrency Concepts in Java
Concurrency Concepts in Java
Doug Hawkins
 
CLS & asyncListener: asynchronous observability for Node.js
CLS & asyncListener: asynchronous observability for Node.jsCLS & asyncListener: asynchronous observability for Node.js
CLS & asyncListener: asynchronous observability for Node.js
Forrest Norvell
 
Building Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaBuilding Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJava
Rick Warren
 
Reactive Java (GeeCON 2014)
Reactive Java (GeeCON 2014)Reactive Java (GeeCON 2014)
Reactive Java (GeeCON 2014)
Tomasz Kowalczewski
 
The Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFuturesThe Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFutures
Haim Yadid
 

What's hot (20)

Reactive Java (33rd Degree)
Reactive Java (33rd Degree)Reactive Java (33rd Degree)
Reactive Java (33rd Degree)
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
 
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListenerNode.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
 
bluespec talk
bluespec talkbluespec talk
bluespec talk
 
Avoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promisesAvoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promises
 
Programming with ZooKeeper - A basic tutorial
Programming with ZooKeeper - A basic tutorialProgramming with ZooKeeper - A basic tutorial
Programming with ZooKeeper - A basic tutorial
 
Counter Wars (JEEConf 2016)
Counter Wars (JEEConf 2016)Counter Wars (JEEConf 2016)
Counter Wars (JEEConf 2016)
 
Understanding greenlet
Understanding greenletUnderstanding greenlet
Understanding greenlet
 
Non Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJavaNon Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJava
 
Callbacks, promises, generators - asynchronous javascript
Callbacks, promises, generators - asynchronous javascriptCallbacks, promises, generators - asynchronous javascript
Callbacks, promises, generators - asynchronous javascript
 
Event loop
Event loopEvent loop
Event loop
 
Reactive programming with RxJava
Reactive programming with RxJavaReactive programming with RxJava
Reactive programming with RxJava
 
Asynchronní programování
Asynchronní programováníAsynchronní programování
Asynchronní programování
 
How to send gzipped requests with boto3
How to send gzipped requests with boto3How to send gzipped requests with boto3
How to send gzipped requests with boto3
 
Reactive programming with RxAndroid
Reactive programming with RxAndroidReactive programming with RxAndroid
Reactive programming with RxAndroid
 
Concurrency Concepts in Java
Concurrency Concepts in JavaConcurrency Concepts in Java
Concurrency Concepts in Java
 
CLS & asyncListener: asynchronous observability for Node.js
CLS & asyncListener: asynchronous observability for Node.jsCLS & asyncListener: asynchronous observability for Node.js
CLS & asyncListener: asynchronous observability for Node.js
 
Building Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaBuilding Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJava
 
Reactive Java (GeeCON 2014)
Reactive Java (GeeCON 2014)Reactive Java (GeeCON 2014)
Reactive Java (GeeCON 2014)
 
The Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFuturesThe Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFutures
 

Similar to Behind modern concurrency primitives

Server side JavaScript: going all the way
Server side JavaScript: going all the wayServer side JavaScript: going all the way
Server side JavaScript: going all the way
Oleg Podsechin
 
Binary Studio Academy: Concurrency in C# 5.0
Binary Studio Academy: Concurrency in C# 5.0Binary Studio Academy: Concurrency in C# 5.0
Binary Studio Academy: Concurrency in C# 5.0
Binary Studio
 
CI Provisioning with OpenStack - Gidi Samuels - OpenStack Day Israel 2016
CI Provisioning with OpenStack - Gidi Samuels - OpenStack Day Israel 2016CI Provisioning with OpenStack - Gidi Samuels - OpenStack Day Israel 2016
CI Provisioning with OpenStack - Gidi Samuels - OpenStack Day Israel 2016
Cloud Native Day Tel Aviv
 
Container orchestration from theory to practice
Container orchestration from theory to practiceContainer orchestration from theory to practice
Container orchestration from theory to practice
Docker, Inc.
 
Async programming and python
Async programming and pythonAsync programming and python
Async programming and python
Chetan Giridhar
 
Phil Basford - machine learning at scale with aws sage maker
Phil Basford - machine learning at scale with aws sage makerPhil Basford - machine learning at scale with aws sage maker
Phil Basford - machine learning at scale with aws sage maker
AWSCOMSUM
 
Seastar @ NYCC++UG
Seastar @ NYCC++UGSeastar @ NYCC++UG
Seastar @ NYCC++UG
Avi Kivity
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applicationsTom Croucher
 
Machine learning at scale with aws sage maker
Machine learning at scale with aws sage makerMachine learning at scale with aws sage maker
Machine learning at scale with aws sage maker
PhilipBasford
 
Avoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jsAvoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.js
cacois
 
Play Framework
Play FrameworkPlay Framework
Play Framework
Harinath Krishnamoorthy
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
Wesley Beary
 
[NDC 2019] Enterprise-Grade Serverless
[NDC 2019] Enterprise-Grade Serverless[NDC 2019] Enterprise-Grade Serverless
[NDC 2019] Enterprise-Grade Serverless
KatyShimizu
 
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
KatyShimizu
 
Workflow as code with Azure Durable Functions
Workflow as code with Azure Durable FunctionsWorkflow as code with Azure Durable Functions
Workflow as code with Azure Durable Functions
Massimo Bonanni
 
Seastar @ SF/BA C++UG
Seastar @ SF/BA C++UGSeastar @ SF/BA C++UG
Seastar @ SF/BA C++UG
Avi Kivity
 
What the CRaC - Superfast JVM startup
What the CRaC - Superfast JVM startupWhat the CRaC - Superfast JVM startup
What the CRaC - Superfast JVM startup
Gerrit Grunwald
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloudfog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloud
Wesley Beary
 
Real World Lessons on the Pain Points of Node.js Applications
Real World Lessons on the Pain Points of Node.js ApplicationsReal World Lessons on the Pain Points of Node.js Applications
Real World Lessons on the Pain Points of Node.js Applications
Ben Hall
 

Similar to Behind modern concurrency primitives (20)

Server side JavaScript: going all the way
Server side JavaScript: going all the wayServer side JavaScript: going all the way
Server side JavaScript: going all the way
 
JS everywhere 2011
JS everywhere 2011JS everywhere 2011
JS everywhere 2011
 
Binary Studio Academy: Concurrency in C# 5.0
Binary Studio Academy: Concurrency in C# 5.0Binary Studio Academy: Concurrency in C# 5.0
Binary Studio Academy: Concurrency in C# 5.0
 
CI Provisioning with OpenStack - Gidi Samuels - OpenStack Day Israel 2016
CI Provisioning with OpenStack - Gidi Samuels - OpenStack Day Israel 2016CI Provisioning with OpenStack - Gidi Samuels - OpenStack Day Israel 2016
CI Provisioning with OpenStack - Gidi Samuels - OpenStack Day Israel 2016
 
Container orchestration from theory to practice
Container orchestration from theory to practiceContainer orchestration from theory to practice
Container orchestration from theory to practice
 
Async programming and python
Async programming and pythonAsync programming and python
Async programming and python
 
Phil Basford - machine learning at scale with aws sage maker
Phil Basford - machine learning at scale with aws sage makerPhil Basford - machine learning at scale with aws sage maker
Phil Basford - machine learning at scale with aws sage maker
 
Seastar @ NYCC++UG
Seastar @ NYCC++UGSeastar @ NYCC++UG
Seastar @ NYCC++UG
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Machine learning at scale with aws sage maker
Machine learning at scale with aws sage makerMachine learning at scale with aws sage maker
Machine learning at scale with aws sage maker
 
Avoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jsAvoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.js
 
Play Framework
Play FrameworkPlay Framework
Play Framework
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
 
[NDC 2019] Enterprise-Grade Serverless
[NDC 2019] Enterprise-Grade Serverless[NDC 2019] Enterprise-Grade Serverless
[NDC 2019] Enterprise-Grade Serverless
 
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
 
Workflow as code with Azure Durable Functions
Workflow as code with Azure Durable FunctionsWorkflow as code with Azure Durable Functions
Workflow as code with Azure Durable Functions
 
Seastar @ SF/BA C++UG
Seastar @ SF/BA C++UGSeastar @ SF/BA C++UG
Seastar @ SF/BA C++UG
 
What the CRaC - Superfast JVM startup
What the CRaC - Superfast JVM startupWhat the CRaC - Superfast JVM startup
What the CRaC - Superfast JVM startup
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloudfog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloud
 
Real World Lessons on the Pain Points of Node.js Applications
Real World Lessons on the Pain Points of Node.js ApplicationsReal World Lessons on the Pain Points of Node.js Applications
Real World Lessons on the Pain Points of Node.js Applications
 

More from Bartosz Sypytkowski

Postgres indexes: how to make them work for your application
Postgres indexes: how to make them work for your applicationPostgres indexes: how to make them work for your application
Postgres indexes: how to make them work for your application
Bartosz Sypytkowski
 
How do databases perform live backups and point-in-time recovery
How do databases perform live backups and point-in-time recoveryHow do databases perform live backups and point-in-time recovery
How do databases perform live backups and point-in-time recovery
Bartosz Sypytkowski
 
Scaling connections in peer-to-peer applications
Scaling connections in peer-to-peer applicationsScaling connections in peer-to-peer applications
Scaling connections in peer-to-peer applications
Bartosz Sypytkowski
 
Rich collaborative data structures for everyone
Rich collaborative data structures for everyoneRich collaborative data structures for everyone
Rich collaborative data structures for everyone
Bartosz Sypytkowski
 
Postgres indexes
Postgres indexesPostgres indexes
Postgres indexes
Bartosz Sypytkowski
 
Collaborative eventsourcing
Collaborative eventsourcingCollaborative eventsourcing
Collaborative eventsourcing
Bartosz Sypytkowski
 
Living in eventually consistent reality
Living in eventually consistent realityLiving in eventually consistent reality
Living in eventually consistent reality
Bartosz Sypytkowski
 
Virtual machines - how they work
Virtual machines - how they workVirtual machines - how they work
Virtual machines - how they work
Bartosz Sypytkowski
 
Short story of time
Short story of timeShort story of time
Short story of time
Bartosz Sypytkowski
 
Collaborative text editing
Collaborative text editingCollaborative text editing
Collaborative text editing
Bartosz Sypytkowski
 
The last mile from db to disk
The last mile from db to diskThe last mile from db to disk
The last mile from db to disk
Bartosz Sypytkowski
 
GraphQL - an elegant weapon... for more civilized age
GraphQL - an elegant weapon... for more civilized ageGraphQL - an elegant weapon... for more civilized age
GraphQL - an elegant weapon... for more civilized age
Bartosz Sypytkowski
 

More from Bartosz Sypytkowski (12)

Postgres indexes: how to make them work for your application
Postgres indexes: how to make them work for your applicationPostgres indexes: how to make them work for your application
Postgres indexes: how to make them work for your application
 
How do databases perform live backups and point-in-time recovery
How do databases perform live backups and point-in-time recoveryHow do databases perform live backups and point-in-time recovery
How do databases perform live backups and point-in-time recovery
 
Scaling connections in peer-to-peer applications
Scaling connections in peer-to-peer applicationsScaling connections in peer-to-peer applications
Scaling connections in peer-to-peer applications
 
Rich collaborative data structures for everyone
Rich collaborative data structures for everyoneRich collaborative data structures for everyone
Rich collaborative data structures for everyone
 
Postgres indexes
Postgres indexesPostgres indexes
Postgres indexes
 
Collaborative eventsourcing
Collaborative eventsourcingCollaborative eventsourcing
Collaborative eventsourcing
 
Living in eventually consistent reality
Living in eventually consistent realityLiving in eventually consistent reality
Living in eventually consistent reality
 
Virtual machines - how they work
Virtual machines - how they workVirtual machines - how they work
Virtual machines - how they work
 
Short story of time
Short story of timeShort story of time
Short story of time
 
Collaborative text editing
Collaborative text editingCollaborative text editing
Collaborative text editing
 
The last mile from db to disk
The last mile from db to diskThe last mile from db to disk
The last mile from db to disk
 
GraphQL - an elegant weapon... for more civilized age
GraphQL - an elegant weapon... for more civilized ageGraphQL - an elegant weapon... for more civilized age
GraphQL - an elegant weapon... for more civilized age
 

Recently uploaded

MCQ Soil mechanics questions (Soil shear strength).pdf
MCQ Soil mechanics questions (Soil shear strength).pdfMCQ Soil mechanics questions (Soil shear strength).pdf
MCQ Soil mechanics questions (Soil shear strength).pdf
Osamah Alsalih
 
ethical hacking-mobile hacking methods.ppt
ethical hacking-mobile hacking methods.pptethical hacking-mobile hacking methods.ppt
ethical hacking-mobile hacking methods.ppt
Jayaprasanna4
 
Governing Equations for Fundamental Aerodynamics_Anderson2010.pdf
Governing Equations for Fundamental Aerodynamics_Anderson2010.pdfGoverning Equations for Fundamental Aerodynamics_Anderson2010.pdf
Governing Equations for Fundamental Aerodynamics_Anderson2010.pdf
WENKENLI1
 
road safety engineering r s e unit 3.pdf
road safety engineering  r s e unit 3.pdfroad safety engineering  r s e unit 3.pdf
road safety engineering r s e unit 3.pdf
VENKATESHvenky89705
 
ML for identifying fraud using open blockchain data.pptx
ML for identifying fraud using open blockchain data.pptxML for identifying fraud using open blockchain data.pptx
ML for identifying fraud using open blockchain data.pptx
Vijay Dialani, PhD
 
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
zwunae
 
Immunizing Image Classifiers Against Localized Adversary Attacks
Immunizing Image Classifiers Against Localized Adversary AttacksImmunizing Image Classifiers Against Localized Adversary Attacks
Immunizing Image Classifiers Against Localized Adversary Attacks
gerogepatton
 
Cosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdfCosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdf
Kamal Acharya
 
ethical hacking in wireless-hacking1.ppt
ethical hacking in wireless-hacking1.pptethical hacking in wireless-hacking1.ppt
ethical hacking in wireless-hacking1.ppt
Jayaprasanna4
 
Pile Foundation by Venkatesh Taduvai (Sub Geotechnical Engineering II)-conver...
Pile Foundation by Venkatesh Taduvai (Sub Geotechnical Engineering II)-conver...Pile Foundation by Venkatesh Taduvai (Sub Geotechnical Engineering II)-conver...
Pile Foundation by Venkatesh Taduvai (Sub Geotechnical Engineering II)-conver...
AJAYKUMARPUND1
 
Hierarchical Digital Twin of a Naval Power System
Hierarchical Digital Twin of a Naval Power SystemHierarchical Digital Twin of a Naval Power System
Hierarchical Digital Twin of a Naval Power System
Kerry Sado
 
Standard Reomte Control Interface - Neometrix
Standard Reomte Control Interface - NeometrixStandard Reomte Control Interface - Neometrix
Standard Reomte Control Interface - Neometrix
Neometrix_Engineering_Pvt_Ltd
 
Water Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation and Control Monthly - May 2024.pdfWater Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation & Control
 
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
thanhdowork
 
AKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdf
AKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdfAKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdf
AKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdf
SamSarthak3
 
Nuclear Power Economics and Structuring 2024
Nuclear Power Economics and Structuring 2024Nuclear Power Economics and Structuring 2024
Nuclear Power Economics and Structuring 2024
Massimo Talia
 
WATER CRISIS and its solutions-pptx 1234
WATER CRISIS and its solutions-pptx 1234WATER CRISIS and its solutions-pptx 1234
WATER CRISIS and its solutions-pptx 1234
AafreenAbuthahir2
 
weather web application report.pdf
weather web application report.pdfweather web application report.pdf
weather web application report.pdf
Pratik Pawar
 
HYDROPOWER - Hydroelectric power generation
HYDROPOWER - Hydroelectric power generationHYDROPOWER - Hydroelectric power generation
HYDROPOWER - Hydroelectric power generation
Robbie Edward Sayers
 
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdfHybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
fxintegritypublishin
 

Recently uploaded (20)

MCQ Soil mechanics questions (Soil shear strength).pdf
MCQ Soil mechanics questions (Soil shear strength).pdfMCQ Soil mechanics questions (Soil shear strength).pdf
MCQ Soil mechanics questions (Soil shear strength).pdf
 
ethical hacking-mobile hacking methods.ppt
ethical hacking-mobile hacking methods.pptethical hacking-mobile hacking methods.ppt
ethical hacking-mobile hacking methods.ppt
 
Governing Equations for Fundamental Aerodynamics_Anderson2010.pdf
Governing Equations for Fundamental Aerodynamics_Anderson2010.pdfGoverning Equations for Fundamental Aerodynamics_Anderson2010.pdf
Governing Equations for Fundamental Aerodynamics_Anderson2010.pdf
 
road safety engineering r s e unit 3.pdf
road safety engineering  r s e unit 3.pdfroad safety engineering  r s e unit 3.pdf
road safety engineering r s e unit 3.pdf
 
ML for identifying fraud using open blockchain data.pptx
ML for identifying fraud using open blockchain data.pptxML for identifying fraud using open blockchain data.pptx
ML for identifying fraud using open blockchain data.pptx
 
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
 
Immunizing Image Classifiers Against Localized Adversary Attacks
Immunizing Image Classifiers Against Localized Adversary AttacksImmunizing Image Classifiers Against Localized Adversary Attacks
Immunizing Image Classifiers Against Localized Adversary Attacks
 
Cosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdfCosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdf
 
ethical hacking in wireless-hacking1.ppt
ethical hacking in wireless-hacking1.pptethical hacking in wireless-hacking1.ppt
ethical hacking in wireless-hacking1.ppt
 
Pile Foundation by Venkatesh Taduvai (Sub Geotechnical Engineering II)-conver...
Pile Foundation by Venkatesh Taduvai (Sub Geotechnical Engineering II)-conver...Pile Foundation by Venkatesh Taduvai (Sub Geotechnical Engineering II)-conver...
Pile Foundation by Venkatesh Taduvai (Sub Geotechnical Engineering II)-conver...
 
Hierarchical Digital Twin of a Naval Power System
Hierarchical Digital Twin of a Naval Power SystemHierarchical Digital Twin of a Naval Power System
Hierarchical Digital Twin of a Naval Power System
 
Standard Reomte Control Interface - Neometrix
Standard Reomte Control Interface - NeometrixStandard Reomte Control Interface - Neometrix
Standard Reomte Control Interface - Neometrix
 
Water Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation and Control Monthly - May 2024.pdfWater Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation and Control Monthly - May 2024.pdf
 
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
 
AKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdf
AKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdfAKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdf
AKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdf
 
Nuclear Power Economics and Structuring 2024
Nuclear Power Economics and Structuring 2024Nuclear Power Economics and Structuring 2024
Nuclear Power Economics and Structuring 2024
 
WATER CRISIS and its solutions-pptx 1234
WATER CRISIS and its solutions-pptx 1234WATER CRISIS and its solutions-pptx 1234
WATER CRISIS and its solutions-pptx 1234
 
weather web application report.pdf
weather web application report.pdfweather web application report.pdf
weather web application report.pdf
 
HYDROPOWER - Hydroelectric power generation
HYDROPOWER - Hydroelectric power generationHYDROPOWER - Hydroelectric power generation
HYDROPOWER - Hydroelectric power generation
 
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdfHybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
 

Behind modern concurrency primitives

  • 2. INTRODUCTION Bartosz Sypytkowski ▪ @Horusiath ▪ b.sypytkowski@gmail.com ▪ bartoszsypytkowski.com
  • 3.  Concurrency in user vs. kernel space  Thread pools  Schedulers  Coroutines  State machines AGENDA
  • 4. WHY DO WE USE THIS?
  • 5. ASYNC/AWAIT Task.Run(async () => { await using var conn = new SqlConnection(ConnectionString); await conn.OpenAsync(); var user = await conn.QueryFirstAsync<User>( "SELECT * FROM Users WHERE Id = @id", new { id = 100 }); Console.WriteLine($"Received user {user.FirstName} {user.LastName}"); });
  • 7. THREAD API new Thread(() => { var conn = new SqlConnection(ConnectionString); conn.Open(); var user = conn.QueryFirst<User>( "SELECT * FROM Users WHERE Id = @id", new { id = 100 }); Console.WriteLine($"Received user {user.FirstName} {user.LastName}"); }).Start();
  • 8. Thread Pool* Managed Thread Managed Thread OS Thread THREADS TASKS User space Kernel space User space Kernel space Managed Thread OS Thread OS Thread Scheduler OS Thread OS Thread OS Thread Task Task Task Task Task Task Task Task Task Task Task Task Task Task Task Task Task Task
  • 10. THREAD POOL BASICS CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Job Queue
  • 11. PINNING THREAD TO CPU var threads = Process.GetCurrentProcess().Threads; var cpuCount = Environment.ProcessorCount; Console.WriteLine($"Using {threads.Count} threads on {cpuCount} cores."); // => Using 10 threads on 4 cores. for (int i = 0; i < threads.Count; i++) { var pthread = threads[i]; var cpuMask = (1L << (i % cpuCount)); pthread.IdealProcessor = i % cpuCount; // set preferred thread(s) pthread.ProcessorAffinity = (IntPtr)cpuMask; // set thread affinity mask } NOTE: it’s not always possible (iOS) or respected.
  • 12. SHARING DATA IN MULTI-CPU ARCHITECTURE
  • 13. HARDWARE ARCHITECTURE 101 CPU 1 L1 cache L1 cache L3 cache CPU 2 L1 cache L1 cache RAM CPU L1 cache: 1ns CPU L2 cache: 4-7ns CPU L2 cache: 100ns
  • 14. HARDWARE ARCHITECTURE NUMA CPU 1 CPU 2 L1-2 cache CPU 3 CPU 4 L1-2 cache CPU 5 CPU 6 L1-2 cache CPU 7 CPU 8 L1-2 cache
  • 16. THREAD POOL WORK STEALING CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Job Job Job Job Job Job Job Job Job Job
  • 17. THREAD POOL WORK STEALING CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Job Job Job Job Job Job ? Job Job Job Empty Queue
  • 18. THREAD POOL WORK STEALING CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Job Job Job Job Job Job ? Job Job Job
  • 19. THREAD POOL WORK STEALING CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Job Job Job Job Job Job Job Job Job
  • 20. COMPAR ING VECTOR CLOCKS AFFINITY BASED THREAD POOL CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread S1 S1 S1 S1 S2 S2 S3 S2 S3 S3 S4 S5 S4 S4 S5 Always map entity to the same thread / core
  • 21. AFFINITY THREAD POOL: PERFORMANCE Source: https://scalac.io/improving-akka-dispatchers/
  • 25. WHY IS THIS CODE BAD? static async Task ProcessFiles(FileInfo[] files) { var tasks = new Task[files.Length]; for (int i = 0; i < files.Length; i++) tasks[i] = ProcessFile(files[i]); await Task.WhenAll(tasks); } static async Task ProcessFile(FileInfo file) { using var stream = file.OpenRead(); using var reader = new StreamReader(stream); var text = reader.ReadToEnd(); Process(text); }
  • 26. WHY IS THIS CODE BAD? static async Task ProcessFiles(FileInfo[] files) { var tasks = new Task[files.Length]; for (int i = 0; i < files.Length; i++) tasks[i] = ProcessFile(files[i]); await Task.WhenAll(tasks); } static async Task ProcessFile(FileInfo file) { using var stream = file.OpenRead(); using var reader = new StreamReader(stream); var text = reader.ReadToEnd(); Process(text); } Blocking the thread belonging to a thread pool shared with other tasks.
  • 27. I/O 1. Just use async I/O API… WHAT CAN WE DO ABOUT IT?
  • 28. I/O 1. Just use async I/O API… 2. … but what when it’s not possible? WHAT CAN WE DO ABOUT IT?
  • 29. I/O 1. Just use async I/O API… 2. … but what when it’s not possible? WHAT CAN WE DO ABOUT IT? internal static class LmdbMethods { [DllImport("lmdb", CallingConvention = CallingConvention.Cdecl)] public static extern int mdb_dbi_open(IntPtr txn, string name, DatabaseOpenFlags flags, out uint db); [DllImport("lmdb", CallingConvention = CallingConvention.Cdecl)] public static extern int mdb_cursor_get(IntPtr cursor, ref ValueStructure key, ref ValueStructure data, CursorOperation op); [DllImport("lmdb", CallingConvention = CallingConvention.Cdecl)] public static extern int mdb_cursor_put(IntPtr cursor, ref ValueStructure key, ref ValueStructure value, CursorPutOptions flags); // other methods }
  • 30. THREAD POOL I/O THREADS CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Managed Thread I/O Threads Managed Thread Managed Thread
  • 31. THREAD POOL I/O THREADS CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Managed Thread I/O Threads Managed Thread Managed Thread J1
  • 32. THREAD POOL I/O THREADS CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Managed Thread I/O Threads Managed Thread Managed Thread J1
  • 33. THREAD POOL I/O THREADS CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Managed Thread I/O Threads Managed Thread Managed Thread J1
  • 34. THREAD POOL I/O THREADS CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Managed Thread I/O Threads Managed Thread Managed Thread J2
  • 35. GOROUTINES & I/O DEALING WITH KERNEL CALLS
  • 36. COMPAR ING VECTOR CLOCKS GOROUTINES I/O CALLS CPU 1 Agent Runtime Thread CPU 2 Agent Runtime Thread CPU 3 Agent Runtime Thread CPU 4 Agent Runtime Thread
  • 37. COMPAR ING VECTOR CLOCKS GOROUTINES I/O CALLS CPU 1 Agent Runtime Thread CPU 2 Agent Runtime Thread CPU 3 Agent Runtime Thread CPU 4 Agent Runtime Thread sys call
  • 38. COMPAR ING VECTOR CLOCKS GOROUTINES I/O CALLS CPU 1 Agent CPU 2 Agent Runtime Thread CPU 3 Agent Runtime Thread CPU 4 Agent Runtime Thread Runtime Thread sys call
  • 39. COMPAR ING VECTOR CLOCKS GOROUTINES I/O CALLS CPU 1 Agent CPU 2 Agent Runtime Thread CPU 3 Agent Runtime Thread CPU 4 Agent Runtime Thread Runtime Thread sys call Runtime Thread
  • 41. Scheduler depends on coroutines to return control to scheduler. PREEMPTIVE Scheduler is in charge of execution. Coroutines can be preempted. COOPERATIVE
  • 42. SCENARIO #2 CREATE AN EXCEL FILE
  • 43. COMPAR ING VECTOR CLOCKS BUILDING AN EXCEL FILE app.get('/valuations.xlsx', async (req, res) => { var workbook = new Excel.Workbook(); var worksheet = workbook.addWorksheet("Valuations"); var valuations = await getValuations(req.params.id); for (let valuation in valuations) { worksheet.addRow(valuation); } await workbook.xlsx.write(res); });
  • 44. COMPAR ING VECTOR CLOCKS BUILDING AN EXCEL FILE app.get('/valuations.xlsx', async (req, res) => { var workbook = new Excel.Workbook(); var worksheet = workbook.addWorksheet("Valuations"); var valuations = await getValuations(req.params.id); for (let valuation in valuations) { worksheet.addRow(valuation); // 500μs } await workbook.xlsx.write(res); });
  • 45. COMPAR ING VECTOR CLOCKS BUILDING AN EXCEL FILE app.get('/valuations.xlsx', async (req, res) => { var workbook = new Excel.Workbook(); var worksheet = workbook.addWorksheet("Valuations"); var valuations = await getValuations(req.params.id); for (let valuation in valuations) { // 20,000 items worksheet.addRow(valuation); // 500μs } await workbook.xlsx.write(res); });
  • 46. COMPAR ING VECTOR CLOCKS BUILDING AN EXCEL FILE app.get('/valuations.xlsx', async (req, res) => { var workbook = new Excel.Workbook(); var worksheet = workbook.addWorksheet("Valuations"); var valuations = await getValuations(req.params.id); for (let valuation in valuations) { // 20,000 items worksheet.addRow(valuation); // 500μs } await workbook.xlsx.write(res); }); Total loop execution time: 10 seconds
  • 47. HOW TO DEAL WITH LONG RUNNING TASKS?
  • 48. LONG RUNNING TASK SEPARATE THREAD CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Scheduler
  • 49. LONG RUNNING TASK SEPARATE THREAD CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Scheduler Task Task.Factory.StartNew(DownloadExcel, TaskCreationOptions.LongRunning)
  • 50. LONG RUNNING TASK SEPARATE THREAD CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Scheduler Task Task.Factory.StartNew(DownloadExcel, TaskCreationOptions.LongRunning) Managed Thread
  • 51. LONG RUNNING TASK SEPARATE THREAD CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Scheduler Managed Thread Task
  • 52. LONG RUNNING TASK SEPARATE THREAD CPU 1 Agent Managed Thread CPU 2 Agent Managed Thread CPU 3 Agent Managed Thread CPU 4 Agent Managed Thread Scheduler Managed Thread Task
  • 53. COMPAR ING VECTOR CLOCKS INTRODUCING INTERRUPTION POINTS function park() { return new Promise((resolve) => setTimeout(resolve, 0)); } app.get('/valuations.xlsx', async (req, res) => { var workbook = new Excel.Workbook(); var worksheet = workbook.addWorksheet("Valuations"); var valuations = await getValuations(req.params.id); var i = 0; for (let valuation in valuations) { // 20,000 items if ((i++) % 100 === 0) { await park(); } worksheet.addRow(valuation); // 500μs } await workbook.xlsx.write(res); });
  • 55. STEP-BASED PREEMPTION % hello world program -module(helloworld). -export([start/0, write/1]). write([]) -> ok; write([File|T]) -> io:fwrite("Writing a file ~p~n", File), write(T). start() -> Files = ["A", "B", "C"], write(Files).
  • 56. STEP-BASED PREEMPTION Reduction counter under the hood % hello world program -module(helloworld). -export([start/0, write/1]). write([], Reductions) -> ok; write([File|T], Reductions) -> % if Reductions == 0 then yield() io:fwrite("Writing a file ~p~n", File), write(T, Reductions-1). start() -> Files = ["A", "B", "C"], write(Files, 2000).
  • 57. • JavaScript promises • .NET Task Parallel Library • Java/Scala Futures PREEMPTIVE • OS threads • Go goroutines • Erlang processes COOPERATIVE
  • 59. let run () = async { let sw = Stopwatch() sw.Start() let t1 = Async.Sleep(5000) let t2 = Async.Sleep(5000) do! t1 do! t2 printfn "Time passed: %ims" sw.ElapsedMilliseconds } static async Task Run() { var sw = new Stopwatch(); sw.Start(); var t1 = Task.Delay(TimeSpan.FromSeconds(5)); var t2 = Task.Delay(TimeSpan.FromSeconds(5)); await t1; await t2; Console.WriteLine( $"Time passed: {sw.ElapsedMilliseconds}ms"); }
  • 60. let run () = async { let sw = Stopwatch() sw.Start() let t1 = Async.Sleep(5000) let t2 = Async.Sleep(5000) do! t1 do! t2 printfn "Time passed: %ims" sw.ElapsedMilliseconds } static async Task Run() { var sw = new Stopwatch(); sw.Start(); var t1 = Task.Delay(TimeSpan.FromSeconds(5)); var t2 = Task.Delay(TimeSpan.FromSeconds(5)); await t1; await t2; Console.WriteLine( $"Time passed: {sw.ElapsedMilliseconds}ms"); } 5 seconds 10 seconds
  • 61. let run () = async { let sw = Stopwatch() sw.Start() let t1 = Async.Sleep(5000) let t2 = Async.Sleep(5000) do! t1 do! t2 printfn "Time passed: %ims" sw.ElapsedMilliseconds } static async Task Run() { var sw = new Stopwatch(); sw.Start(); var t1 = Task.Delay(TimeSpan.FromSeconds(5)); var t2 = Task.Delay(TimeSpan.FromSeconds(5)); await t1; await t2; Console.WriteLine( $"Time passed: {sw.ElapsedMilliseconds}ms"); } EAGER LAZY 5 seconds 10 seconds
  • 63. COMPAR ING VECTOR CLOCKS STACKLESS COROUTINES OLD CALLBACK API app.get('/valuations.xlsx', function (req, res, next) { var workbook = new Excel.Workbook(); var worksheet = workbook.addWorksheet("Valuations"); getValuations(req.params.id, function (err, valuations) { for (let valuation in valuations) { worksheet.addRow(valuation); } workbook.xlsx.write(res, function (err) { next(); }); }); });
  • 64. COMPAR ING VECTOR CLOCKS STACKLESS COROUTINES app.get('/valuations.xlsx', (req, res) => { var workbook = new Excel.Workbook(); var worksheet = workbook.addWorksheet("Valuations"); return getValuations(req.params.id) .then((valuations) => { for (let valuation in valuations) { worksheet.addRow(valuation); } return workbook.xlsx.write(res); }); }); OLD PROMISE API
  • 65. COMPAR ING VECTOR CLOCKS STACKLESS COROUTINES app.get('/valuations.xlsx', async (req, res) => { var workbook = new Excel.Workbook(); var worksheet = workbook.addWorksheet("Valuations"); var valuations = await getValuations(req.params.id); for (let valuation in valuations) { worksheet.addRow(valuation); } await workbook.xlsx.write(res); });
  • 66. PROBLEM OF FUNCTION COLOURING
  • 67. STACKFUL COROUTINES STACK main activation frame function foo(a, b) print("foo", a) bar("foo", b) end function bar(caller, x) print(“bar: ", caller) coroutine.yield() print(“bar", x) end co = coroutine.create(foo) coroutine.resume(co, 1, 2) print(“main”) coroutine.resume(co)
  • 68. STACKFUL COROUTINES STACK main activation frame function foo(a, b) print("foo", a) bar("foo", b) end function bar(caller, x) print(“bar: ", caller) coroutine.yield() print(“bar", x) end co = coroutine.create(foo) coroutine.resume(co, 1, 2) print(“main”) coroutine.resume(co) foo activation frame Start of coroutine stack
  • 69. STACKFUL COROUTINES STACK main activation frame function foo(a, b) print("foo", a) bar("foo", b) end function bar(caller, x) print(“bar: ", caller) coroutine.yield() print(“bar", x) end co = coroutine.create(foo) coroutine.resume(co, 1, 2) print(“main”) coroutine.resume(co) foo activation frame print activation frame
  • 70. STACKFUL COROUTINES STACK main activation frame function foo(a, b) print("foo", a) bar("foo", b) end function bar(caller, x) print(“bar: ", caller) coroutine.yield() print(“bar", x) end co = coroutine.create(foo) coroutine.resume(co, 1, 2) print(“main”) coroutine.resume(co) foo activation frame bar activation frame
  • 71. STACKFUL COROUTINES STACK main activation frame function foo(a, b) print("foo", a) bar("foo", b) end function bar(caller, x) print(“bar: ", caller) coroutine.yield() print(“bar", x) end co = coroutine.create(foo) coroutine.resume(co, 1, 2) print(“main”) coroutine.resume(co) foo activation frame bar activation frame print activation frame
  • 72. STACKFUL COROUTINES STACK main activation frame function foo(a, b) print("foo", a) bar("foo", b) end function bar(caller, x) print(“bar: ", caller) coroutine.yield() print(“bar", x) end co = coroutine.create(foo) coroutine.resume(co, 1, 2) print(“main”) coroutine.resume(co) foo activation frame bar activation frame Park coroutine stack
  • 73. STACKFUL COROUTINES STACK main activation frame function foo(a, b) print("foo", a) bar("foo", b) end function bar(caller, x) print(“bar: ", caller) coroutine.yield() print(“bar", x) end co = coroutine.create(foo) coroutine.resume(co, 1, 2) print(“main”) coroutine.resume(co) foo activation frame bar activation frame Park coroutine stack
  • 74. STACKFUL COROUTINES STACK main activation frame function foo(a, b) print("foo", a) bar("foo", b) end function bar(caller, x) print(“bar: ", caller) coroutine.yield() print(“bar", x) end co = coroutine.create(foo) coroutine.resume(co, 1, 2) print(“main”) coroutine.resume(co) foo activation frame bar activation frame
  • 75. STACKFUL COROUTINES STACK main activation frame function foo(a, b) print("foo", a) bar("foo", b) end function bar(caller, x) print(“bar: ", caller) coroutine.yield() print(“bar", x) end co = coroutine.create(foo) coroutine.resume(co, 1, 2) print(“main”) coroutine.resume(co) foo activation frame bar activation frame print activation frame
  • 76. STACKFUL COROUTINES STACK main activation frame function foo(a, b) print("foo", a) bar("foo", b) end function bar(caller, x) print(“bar: ", caller) coroutine.yield() print(“bar", x) end co = coroutine.create(foo) coroutine.resume(co, 1, 2) print(“main”) coroutine.resume(co) foo activation frame bar activation frame Resume coroutine stack
  • 77. STACKFUL COROUTINES STACK main activation frame function foo(a, b) print("foo", a) bar("foo", b) end function bar(caller, x) print(“bar: ", caller) coroutine.yield() print(“bar", x) end co = coroutine.create(foo) coroutine.resume(co, 1, 2) print(“main”) coroutine.resume(co) foo activation frame bar activation frame
  • 78. STACKFUL COROUTINES STACK main activation frame function foo(a, b) print("foo", a) bar("foo", b) end function bar(caller, x) print(“bar: ", caller) coroutine.yield() print(“bar", x) end co = coroutine.create(foo) coroutine.resume(co, 1, 2) print(“main”) coroutine.resume(co) foo activation frame bar activation frame print activation frame
  • 79. WHAT IS THE CORRECT STACK SIZE FOR EACH COROUTINE?
  • 80. • JavaScript promises • .NET Task Parallel Library • Java/Scala Futures STACKFUL • Go goroutines • LUA coroutines • (soon) Java Loom project STACKLESS
  • 82. ASYNC/AWAIT UNITY COROUTINES IEnumerable WaitAndPrint() { print("Starting at " + Time.time); yield return new WaitForSeconds(0.1f); print("Ending at " + Time.time); } async Task WaitAndPrint() { Console.WriteLine("Starting at " + DateTime.Now); await Task.Delay(100); Console.WriteLine("Ending at " + DateTime.Now); }
  • 83. INTEGRATING TPL AND LINQ public static class TaskExtensions { public static Task<T3> SelectMany<T1, T2, T3>( this Task<T1> task, Func<T1, Task<T2>> binding, Func<T1, T2, T3> combine) { var tcs = new TaskCompletionSource<T3>(); task.ContinueWith(t1 => { if (t1.IsFaulted) tcs.SetException(t1.Exception); else if (t1.IsCanceled) tcs.SetCanceled(); else binding(t1.Result).ContinueWith(t2 => { if (t2.IsFaulted) tcs.SetException(t2.Exception); else if (t2.IsCanceled) tcs.SetCanceled(); else tcs.SetResult(combine(t1.Result, t2.Result)); }); }); return tcs.Task; } } public static Task Rename(int userId, string name) { return from user in GetUser(userId) from _ in SaveUser(user with { Name = name }) select 0; }
  • 85. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 86. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 87. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 88. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 89. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 90. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 91. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 92. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 93. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 94. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 95. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 96. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 97. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 98. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 99. WHAT YOU SEE WHAT YOU DON’T SEE static class Program { static async Task Foo(int a, int b) { Console.WriteLine("Foo", a); await Task.Yield(); Console.WriteLine("Foo", b); } } struct Foo__0 : IStateMachine { AsyncTaskMethodBuilder builder; int state; int a; int b; public void MoveNext() { switch (this.state) { case -1: Console.WriteLine("Foo", this.a); var awaiter = Taks.Yield().GetAwaiter(); this.state = 0; this.builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // ^ awaiter.OnComplete(() => // ThreadPool.QueueUserWorkItem(this.MoveNext)); return; case 0: Console.WriteLine("Foo", this.b); builder.SetResult(); return; } } } static class Program { static Task Foo(int a, int b) { var builder = AsyncTaskMethodBuilder.Create(); var stateMachine = new Foo__0(); // initialize state machine fields stateMachine.a = a; stateMachine.b = b; stateMachine.state = -1; stateMachine.builder = builder; builder.Start(ref stateMachine); // ^ similar to: ThreadPool.QueueUserWorkItem(this.MoveNext); return builder.Task; } }
  • 100. AWAITER PATTERN Custom awaitable objects public readonly struct PromiseAwaiter<T> : INotifyCompletion { private readonly Promise<T> promise; public PromiseAwaiter(Promise<T> promise) { this.promise = promise; } #region mandatory awaiter methods public bool IsCompleted => promise.IsCompleted; public T GetResult() => promise.Result; public void OnCompleted(Action continuation) => promise.RegisterContinuation(continuation); #endregion }
  • 101. ASYNC METHOD BUILDER Custom async methods public struct PromiseAsyncMethodBuilder<T> { private Promise<T>? promise; #region mandatory methods for async state machine builder public static PromiseAsyncMethodBuilder<T> Create() => default; public Promise<T> Task => promise ??= new Promise<T>(); public void SetException(Exception e) => Task.TrySetException(e); public void SetResult(T result) => Task.TrySetResult(result); public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { } public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { } public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { } public void SetStateMachine(IAsyncStateMachine stateMachine) { } #endregion }
  • 104.  Custom AsyncMethodBuilder “docs”: https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md  Building custom (affine) thread pool: https://bartoszsypytkowski.com/thread-safety-with-affine-thread-pools/  What color is your function?: https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/  How Go scheduler works: https://www.youtube.com/watch?v=-K11rY57K7k  Thread per core architecture: https://www.datadoghq.com/blog/engineering/introducing-glommio/ REFERENCES