ASYNC
Jan Škrášek
@hrachcz
ASYNC
ASYNC JS, PHP
ASYNC JS, C#
ASYNC Kotlin
ASYNC PHP #2
ASYNC
Kolik potřebuji vláken?
Potřebuji k tomu speciální syntaxi v jazyce?
Asynchronous programming
“not existing or occurring at the same time”
Threads
https://en.wikipedia.org/wiki/Thread_(computing)
● Drahé
● Omezené
Async
thread
● Vlastnost jazyka / runtime
● Levné
● Téměř neomezené
Async callbacks
btn.setOnClickListener {
btn.text = "World"
}
btn.text = "Hello"
fetch(uri)
.then({ response ->
response.json()
})
.then({ json ->
val key = json["key"]
})
Async Callback + Promise
Async - EventLoop
while (!taskQueue.isEmpty()) {
val task = taskQueue.dequeue()
task.run()
if (!task->isFinished()) {
taskQueue.enqueue(task)
}
}
Javascript / NodeJS
NodeJS: io & cpu threads for internal functions
Javascript: WebWorkers
Image source: http://synsem.com/SyncNotAsync/
Async - syntax sugar
● CALLBACK
● PROMISE - CALLBACK
● YIELD
● ASYNC AWAIT
● SUSPEND / COROUTINES
Async Expression - YIELD
function download(): Generator {
$download = start_download();
while (true) {
yield;
if (is_download_finished($download)) {
return get_download_status($download);
}
}
}
Async Examples - YIELD
function downloadAndParse(): string {
$response = download(); // is Generator
return json_decode($response) // ???
}
Async Examples - YIELD
function downloadAndParse() {
$response = runAndGet(download());
return json_decode($response)
}
function runAndGet(Generator $generator) {
while ($gen->valid()) $gen->next();
sleep(1);
return $generator->getReturn();
}
Async Examples - YIELD
function downloadAndParse(): Generator {
$generator = download();
yield from $generator;
$response = $generator->getReturn();
return json_decode($response)
}
Async Examples - YIELD
function downloadAndParse(): Generator {
$generator = download();
$response = yield from $generator;
return json_decode($response)
}
YIELD keywords
● PHP
○ yield
○ yield from
○ Generator; getReturn()
● Javascript
○ function*
○ yield
○ yield*
○ result = yield* download();
ASYNC / AWAIT - a syntax sugar 🍬🍭🍩
async function downloadAndParse() {
$response = await download();
return json_decode($response)
}
ASYNC / AWAIT - wrapping callbacks 🍬🍭🍩
async function sleep(miliseconds) {
return new Promise(function(resolve) {
setTimeout(()=>{resolve()}, miliseconds)
});
}
(async () => {
await sleep(2000);
// do something
})()
ASYNC / AWAIT - a syntax sugar 🍬🍭🍩
- Awaitnout funkci mohu spustit pouze z jiné async funkce
nebo async scope
- Async scope:
C#: async main(), async UI events
JS: (async () => { … })() - top-level funkce co nikdy
nerejectuje; nebo pouzit API z Promise
Kotlin: async main(), coroutine launchers
ASYNC / AWAIT - C# - task it all 💻💻💻
- Async funkce vrací Task<T>
- ± Promise instance
- await rozbalí
ASYNC / AWAIT - C# - wrap a callback
public Task<HttpResponse> LoadHtmlAsync(string url)
{
var task = new TaskCompletionSource<HttpResponse>();
LoadHtml(url, result => { task.SetResult(result); });
return task.Task;
}
C#: So, we are ready to … or?
● Cancellation
● Task allocation
● Thread switching
C# ASYNC: cancellation
void Autocomplete(text: string) {
// cancel previous search task
var searchTask = SearchAsync(text);
var result = await searchTask;
// process result
}
C# ASYNC: cancellation
private CancellationTokenSource? cts = null
void Autocomplete(text: string) {
cts?.Cancel()
cts = new CancellationTokenSource();
try {
var result = await SearchAsync(text, cts.Token);
// process result
} catch (OperationCanceledException) {
} finally { cts?.Dispose() }
}
C# ASYNC: task allocation
public async Task<bool> MoveNextAsync()
{
if (_bufferedCount == 0)
{
await FillBuffer();
}
return _bufferedCount > 0;
}
C# ASYNC: task allocation
public async Task<bool> MoveNextAsync()
{
if (_bufferedCount == 0)
{
await FillBuffer();
}
return _bufferedCount > 0;
}
C# ASYNC: task allocation
public async ValueTask<bool> MoveNextAsync()
{
if (_bufferedCount == 0)
{
await FillBuffer();
}
return _bufferedCount > 0;
}
Parallel ASYNC AWAIT
- Main (UI) thread
- Jumping to different threads
C# ASYNC: thread switching
private async void button1_Click(object sender, EventArgs e
{
Button1.enabled = false;
await SynchronizeAsync();
Button1.enabled = true;
}
C# ASYNC: thread switching
C# ASYNC: thread switching
private async void button1_Click(object sender, EventArgs e
{
…
}
async Task Synchronize()
{
Task.Run(() => { … })
…
await httpRequest.executeAsync().configureAwait(false)
}
How it works - internally
https://www.markopapic.com/csharp-under-the-hood-async-await/
static async Task BarAsync()
{
Console.WriteLine("This happens before await");
int i = await QuxAsync();
Console.WriteLine("This happens after await. The result of
await is " + i);
}
static Task BarAsync()
{
Program.<BarAsync>d__2 stateMachine;
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start<Program.<BarAsync>d__2>(ref
stateMachine);
return stateMachine.<>t__builder.Task;
}
private struct <BarAsync>d__2 : IAsyncStateMachine {
public int <>1__state;
public AsyncTaskMethodBuilder <>t__builder;
private TaskAwaiter<int> <>u__1;
void IAsyncStateMachine.MoveNext()
{
int num1 = this.<>1__state;
try {
TaskAwaiter<int> awaiter;
int num2;
if (num1 != 0)
{
Console.WriteLine("This happens before await");
awaiter = Program.QuxAsync().GetAwaiter();
if (num1 != 0)
{
Console.WriteLine("This happens before await");
awaiter = Program.QuxAsync().GetAwaiter();
if (!awaiter.IsCompleted){
this.<>1__state = num2 = 0;
this.<>u__1 = awaiter;
this.<>t__builder.AwaitUnsafeOnCompleted(ref await..
return;
}
}else{
awaiter = this.<>u__1;
this.<>u__1 = new TaskAwaiter<int>();
this.<>1__state = num2 = -1;
}
if (num1 != 0)
{
Console.WriteLine("This happens before await");
awaiter = Program.QuxAsync().GetAwaiter();
if (!awaiter.IsCompleted){
…
return;
}
}else{
awaiter = this.<>u__1;
this.<>u__1 = new TaskAwaiter<int>();
this.<>1__state = num2 = -1;
}
Console.WriteLine("This happens after await. The result of
await is " + (object) awaiter.GetResult());
Kotlin & Coroutines 💖
Implictní await!
Kotlin & Coroutines
suspend fun download(): HttpResponse {
}
suspend fun myFun() {
val response = download()
}
Kotlin & Coroutines
fun download(c: Continuation<HttpResponse>): HttpResponse {
}
interface Continuation<in T> {
val context: CoroutineContext
fun resume(value: T)
fun resumeWithException(exception: Throwable)
}
Kotlin & Coroutines
suspend fun search(test: String): HttpResponse {
}
private var job: Job? = null
fun autocomplete(text: String) {
job?.cancel()
job = GlobalScope.launch(Dispatchers.IO) {
val response = download(text: String)
...
}
}
Kotlin & Coroutines
fun search(test: String): Deferred<HttpResponse> {
}
private var job: Job? = null
fun autocomplete(text: String) {
job?.cancel()
job = GlobalScope.launch(Dispatchers.IO) {
val response = download(text: String).await()
...
}
}
Kotlin & Coroutines
val jobs = mutableListOf<Deferred<Int>>()
for (i in 0..1_000_000) {
jobs += GlobalScope.async(Dispatchers.Default) {
i + 1
}
}
val nums = jobs.map { it.await() }
https://pl.kotl.in/sf0502yYI
Kotlin & Coroutines
suspend fun fetchId(): Int {
return suspendCoroutine{ continuation ->
api.send(
uri,
{ continuation.resume(it) }
)
}
}
PHP
😶
PHP - async s callbacky
- Potrebuji nejaky event loop
- Tzn. nekde zacne bezet run(), ktere nekonci, dokud jsou tasky
ReactPHP
$loop = ReactEventLoopFactory::create();
$server = new ReactHttpServer(function
(ServerRequestInterface $r) {
...
return new ReactHttpResponse(...);
});
$socket = new ReactSocketServer(8080, $loop);
$server->listen($socket);
echo "Server running at http://127.0.0.1:8080n";
$loop->run();
ReactPHP
PHP a ASYNC - amphp
AmpLoop::run(function() {
$config = AmpMysqlConnectionConfig::fromString("host=
$pool = AmpMysqlpool($config);
$statement = yield $pool->prepare("SELECT * FROM table
$result = yield $statement->execute([1337]);
while (yield $result->advance()) {
$row = $result->getCurrent();
}
});
PHP a ASYNC - amphp
class Promise {
public $result = "Test";
}
function test(): Generator {
$promise = new Promise();
$result = yield $promise;
var_dump($result);
}
$gen = test();
// RUN implementation
$p1 = $gen->current();
$gen->send($p1->result);
PHP a ASYNC - amphp
function test(): Promise {
return Ampcall(function() {
$promise = new Promise();
$result = yield $promise;
var_dump($result);
});
}
Reading
https://github.com/juzna/nette-sandbox-flow/
https://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PH
P.html
What’s next
● RUST
● GO
● Avoid shared state - flows, RX, channels, ...
Jaké máte otázky?
Díky za pozornost!
Twitter @hrachcz
GitHub hrach

Asynchronní programování

  • 1.
  • 2.
    ASYNC ASYNC JS, PHP ASYNCJS, C# ASYNC Kotlin ASYNC PHP #2
  • 3.
    ASYNC Kolik potřebuji vláken? Potřebujik tomu speciální syntaxi v jazyce?
  • 4.
    Asynchronous programming “not existingor occurring at the same time”
  • 5.
  • 6.
    Async thread ● Vlastnost jazyka/ runtime ● Levné ● Téměř neomezené
  • 7.
  • 8.
    fetch(uri) .then({ response -> response.json() }) .then({json -> val key = json["key"] }) Async Callback + Promise
  • 9.
    Async - EventLoop while(!taskQueue.isEmpty()) { val task = taskQueue.dequeue() task.run() if (!task->isFinished()) { taskQueue.enqueue(task) } }
  • 10.
    Javascript / NodeJS NodeJS:io & cpu threads for internal functions Javascript: WebWorkers Image source: http://synsem.com/SyncNotAsync/
  • 11.
    Async - syntaxsugar ● CALLBACK ● PROMISE - CALLBACK ● YIELD ● ASYNC AWAIT ● SUSPEND / COROUTINES
  • 12.
    Async Expression -YIELD function download(): Generator { $download = start_download(); while (true) { yield; if (is_download_finished($download)) { return get_download_status($download); } } }
  • 13.
    Async Examples -YIELD function downloadAndParse(): string { $response = download(); // is Generator return json_decode($response) // ??? }
  • 14.
    Async Examples -YIELD function downloadAndParse() { $response = runAndGet(download()); return json_decode($response) } function runAndGet(Generator $generator) { while ($gen->valid()) $gen->next(); sleep(1); return $generator->getReturn(); }
  • 15.
    Async Examples -YIELD function downloadAndParse(): Generator { $generator = download(); yield from $generator; $response = $generator->getReturn(); return json_decode($response) }
  • 16.
    Async Examples -YIELD function downloadAndParse(): Generator { $generator = download(); $response = yield from $generator; return json_decode($response) }
  • 17.
    YIELD keywords ● PHP ○yield ○ yield from ○ Generator; getReturn() ● Javascript ○ function* ○ yield ○ yield* ○ result = yield* download();
  • 18.
    ASYNC / AWAIT- a syntax sugar 🍬🍭🍩 async function downloadAndParse() { $response = await download(); return json_decode($response) }
  • 19.
    ASYNC / AWAIT- wrapping callbacks 🍬🍭🍩 async function sleep(miliseconds) { return new Promise(function(resolve) { setTimeout(()=>{resolve()}, miliseconds) }); } (async () => { await sleep(2000); // do something })()
  • 20.
    ASYNC / AWAIT- a syntax sugar 🍬🍭🍩 - Awaitnout funkci mohu spustit pouze z jiné async funkce nebo async scope - Async scope: C#: async main(), async UI events JS: (async () => { … })() - top-level funkce co nikdy nerejectuje; nebo pouzit API z Promise Kotlin: async main(), coroutine launchers
  • 21.
    ASYNC / AWAIT- C# - task it all 💻💻💻 - Async funkce vrací Task<T> - ± Promise instance - await rozbalí
  • 22.
    ASYNC / AWAIT- C# - wrap a callback public Task<HttpResponse> LoadHtmlAsync(string url) { var task = new TaskCompletionSource<HttpResponse>(); LoadHtml(url, result => { task.SetResult(result); }); return task.Task; }
  • 23.
    C#: So, weare ready to … or? ● Cancellation ● Task allocation ● Thread switching
  • 24.
    C# ASYNC: cancellation voidAutocomplete(text: string) { // cancel previous search task var searchTask = SearchAsync(text); var result = await searchTask; // process result }
  • 25.
    C# ASYNC: cancellation privateCancellationTokenSource? cts = null void Autocomplete(text: string) { cts?.Cancel() cts = new CancellationTokenSource(); try { var result = await SearchAsync(text, cts.Token); // process result } catch (OperationCanceledException) { } finally { cts?.Dispose() } }
  • 26.
    C# ASYNC: taskallocation public async Task<bool> MoveNextAsync() { if (_bufferedCount == 0) { await FillBuffer(); } return _bufferedCount > 0; }
  • 27.
    C# ASYNC: taskallocation public async Task<bool> MoveNextAsync() { if (_bufferedCount == 0) { await FillBuffer(); } return _bufferedCount > 0; }
  • 28.
    C# ASYNC: taskallocation public async ValueTask<bool> MoveNextAsync() { if (_bufferedCount == 0) { await FillBuffer(); } return _bufferedCount > 0; }
  • 29.
    Parallel ASYNC AWAIT -Main (UI) thread - Jumping to different threads
  • 30.
    C# ASYNC: threadswitching private async void button1_Click(object sender, EventArgs e { Button1.enabled = false; await SynchronizeAsync(); Button1.enabled = true; }
  • 31.
  • 32.
    C# ASYNC: threadswitching private async void button1_Click(object sender, EventArgs e { … } async Task Synchronize() { Task.Run(() => { … }) … await httpRequest.executeAsync().configureAwait(false) }
  • 33.
    How it works- internally https://www.markopapic.com/csharp-under-the-hood-async-await/
  • 34.
    static async TaskBarAsync() { Console.WriteLine("This happens before await"); int i = await QuxAsync(); Console.WriteLine("This happens after await. The result of await is " + i); }
  • 35.
    static Task BarAsync() { Program.<BarAsync>d__2stateMachine; stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start<Program.<BarAsync>d__2>(ref stateMachine); return stateMachine.<>t__builder.Task; }
  • 36.
    private struct <BarAsync>d__2: IAsyncStateMachine { public int <>1__state; public AsyncTaskMethodBuilder <>t__builder; private TaskAwaiter<int> <>u__1; void IAsyncStateMachine.MoveNext() { int num1 = this.<>1__state; try { TaskAwaiter<int> awaiter; int num2; if (num1 != 0) { Console.WriteLine("This happens before await"); awaiter = Program.QuxAsync().GetAwaiter();
  • 37.
    if (num1 !=0) { Console.WriteLine("This happens before await"); awaiter = Program.QuxAsync().GetAwaiter(); if (!awaiter.IsCompleted){ this.<>1__state = num2 = 0; this.<>u__1 = awaiter; this.<>t__builder.AwaitUnsafeOnCompleted(ref await.. return; } }else{ awaiter = this.<>u__1; this.<>u__1 = new TaskAwaiter<int>(); this.<>1__state = num2 = -1; }
  • 38.
    if (num1 !=0) { Console.WriteLine("This happens before await"); awaiter = Program.QuxAsync().GetAwaiter(); if (!awaiter.IsCompleted){ … return; } }else{ awaiter = this.<>u__1; this.<>u__1 = new TaskAwaiter<int>(); this.<>1__state = num2 = -1; } Console.WriteLine("This happens after await. The result of await is " + (object) awaiter.GetResult());
  • 39.
    Kotlin & Coroutines💖 Implictní await!
  • 40.
    Kotlin & Coroutines suspendfun download(): HttpResponse { } suspend fun myFun() { val response = download() }
  • 41.
    Kotlin & Coroutines fundownload(c: Continuation<HttpResponse>): HttpResponse { } interface Continuation<in T> { val context: CoroutineContext fun resume(value: T) fun resumeWithException(exception: Throwable) }
  • 42.
    Kotlin & Coroutines suspendfun search(test: String): HttpResponse { } private var job: Job? = null fun autocomplete(text: String) { job?.cancel() job = GlobalScope.launch(Dispatchers.IO) { val response = download(text: String) ... } }
  • 43.
    Kotlin & Coroutines funsearch(test: String): Deferred<HttpResponse> { } private var job: Job? = null fun autocomplete(text: String) { job?.cancel() job = GlobalScope.launch(Dispatchers.IO) { val response = download(text: String).await() ... } }
  • 44.
    Kotlin & Coroutines valjobs = mutableListOf<Deferred<Int>>() for (i in 0..1_000_000) { jobs += GlobalScope.async(Dispatchers.Default) { i + 1 } } val nums = jobs.map { it.await() } https://pl.kotl.in/sf0502yYI
  • 45.
    Kotlin & Coroutines suspendfun fetchId(): Int { return suspendCoroutine{ continuation -> api.send( uri, { continuation.resume(it) } ) } }
  • 46.
  • 47.
    PHP - asyncs callbacky - Potrebuji nejaky event loop - Tzn. nekde zacne bezet run(), ktere nekonci, dokud jsou tasky
  • 48.
    ReactPHP $loop = ReactEventLoopFactory::create(); $server= new ReactHttpServer(function (ServerRequestInterface $r) { ... return new ReactHttpResponse(...); }); $socket = new ReactSocketServer(8080, $loop); $server->listen($socket); echo "Server running at http://127.0.0.1:8080n"; $loop->run();
  • 49.
  • 50.
    PHP a ASYNC- amphp AmpLoop::run(function() { $config = AmpMysqlConnectionConfig::fromString("host= $pool = AmpMysqlpool($config); $statement = yield $pool->prepare("SELECT * FROM table $result = yield $statement->execute([1337]); while (yield $result->advance()) { $row = $result->getCurrent(); } });
  • 51.
    PHP a ASYNC- amphp class Promise { public $result = "Test"; } function test(): Generator { $promise = new Promise(); $result = yield $promise; var_dump($result); } $gen = test(); // RUN implementation $p1 = $gen->current(); $gen->send($p1->result);
  • 52.
    PHP a ASYNC- amphp function test(): Promise { return Ampcall(function() { $promise = new Promise(); $result = yield $promise; var_dump($result); }); }
  • 53.
  • 54.
    What’s next ● RUST ●GO ● Avoid shared state - flows, RX, channels, ...
  • 55.
  • 56.
    Díky za pozornost! Twitter@hrachcz GitHub hrach