Last active
April 12, 2022 19:21
-
-
Save ryszardmakuch/eeada8ec807a658f3d2ca0f544b627c3 to your computer and use it in GitHub Desktop.
Coroutines
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Coroutines: | |
How do Kotlin coroutines work internally? | |
- https://medium.com/@elizarov/blocking-threads-suspending-coroutines-d33e11bf4761, | |
- https://medium.com/androiddevelopers/coroutines-on-android-part-i-getting-the-background-3e0e54d20bb, | |
- https://medium.com/androiddevelopers/coroutines-on-android-part-ii-getting-started-3bff117176dd, | |
- https://medium.com/androiddevelopers/coroutines-on-android-part-iii-real-work-2ba8a2ec2f45, | |
- https://medium.com/@patson.luk/learning-kotlin-coroutines-as-a-java-dev-part-i-a04029b6214b, | |
- https://medium.com/@patson.luk/learning-kotlin-coroutines-as-a-java-dev-part-ii-dfe0d468b65e, | |
- https://medium.com/@esocogmbh/coroutines-in-pure-java-65661a379c85. | |
## Coroutines suspending state machines: | |
- https://labs.pedrofelix.org/guides/kotlin/coroutines/coroutines-and-state-machines, | |
- https://medium.com/google-developer-experts/coroutines-suspending-state-machines-36b189f8aa60. | |
## Structured concurrency: | |
- https://www.youtube.com/watch?v=Mj5P47F6nJg, | |
- https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/, | |
- https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/, | |
- https://libdill.org/structured-concurrency.html. | |
# Loom | |
- https://wiki.openjdk.java.net/display/loom/Main, | |
- https://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part1.html, | |
- https://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part2.html, | |
- https://renato.athaydes.com/posts/taking-loom-for-a-spin.html, | |
- https://blog.usejournal.com/project-loom-virtual-threads-in-java-371dccc88b0f. |
// CoroutinesKt$main$time$1$1.java
package pl.rmakuch;
import kotlin.Metadata;
import kotlin.ResultKt;
import kotlin.Unit;
import kotlin.coroutines.Continuation;
import kotlin.coroutines.intrinsics.IntrinsicsKt;
import kotlin.coroutines.jvm.internal.DebugMetadata;
import kotlin.coroutines.jvm.internal.SuspendLambda;
import kotlin.jvm.functions.Function2;
import kotlin.jvm.internal.Intrinsics;
import kotlinx.coroutines.CoroutineScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@DebugMetadata(
f = "Coroutines.kt",
l = {10},
i = {0},
s = {"L$0"},
n = {"$this$runBlocking"},
m = "invokeSuspend",
c = "pl.rmakuch.CoroutinesKt$main$time$1$1"
)
@Metadata(
mv = {1, 1, 16},
bv = {1, 0, 3},
k = 3,
d1 = {"\u0000\u000e\n\u0000\n\u0002\u0010\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\u0010\u0000\u001a\u00020\u0001*\u00020\u0002H\u008a@¢\u0006\u0004\b\u0003\u0010\u0004"},
d2 = {"<anonymous>", "", "Lkotlinx/coroutines/CoroutineScope;", "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"}
)
final class CoroutinesKt$main$time$1$1 extends SuspendLambda implements Function2 {
private CoroutineScope p$;
Object L$0;
int label;
@Nullable
public final Object invokeSuspend(@NotNull Object $result) {
Object var3 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
CoroutineScope $this$runBlocking;
switch(this.label) {
case 0:
ResultKt.throwOnFailure($result);
$this$runBlocking = this.p$;
this.L$0 = $this$runBlocking;
this.label = 1;
if (CoroutinesKt.parent(this) == var3) {
return var3;
}
break;
case 1:
$this$runBlocking = (CoroutineScope)this.L$0;
ResultKt.throwOnFailure($result);
break;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
return Unit.INSTANCE;
}
CoroutinesKt$main$time$1$1(Continuation var1) {
super(2, var1);
}
@NotNull
public final Continuation create(@Nullable Object value, @NotNull Continuation completion) {
Intrinsics.checkParameterIsNotNull(completion, "completion");
CoroutinesKt$main$time$1$1 var3 = new CoroutinesKt$main$time$1$1(completion);
var3.p$ = (CoroutineScope)value;
return var3;
}
public final Object invoke(Object var1, Object var2) {
return ((CoroutinesKt$main$time$1$1)this.create(var1, (Continuation)var2)).invokeSuspend(Unit.INSTANCE);
}
}
// CoroutinesKt.java
package pl.rmakuch;
import java.util.concurrent.TimeUnit;
import kotlin.Metadata;
import kotlin.ResultKt;
import kotlin.Unit;
import kotlin.coroutines.Continuation;
import kotlin.coroutines.CoroutineContext;
import kotlin.coroutines.intrinsics.IntrinsicsKt;
import kotlin.coroutines.jvm.internal.ContinuationImpl;
import kotlin.jvm.functions.Function2;
import kotlin.jvm.internal.Intrinsics;
import kotlinx.coroutines.BuildersKt;
import kotlinx.coroutines.CoroutineScope;
import kotlinx.coroutines.CoroutineStart;
import kotlinx.coroutines.Deferred;
import kotlinx.coroutines.DelayKt;
import kotlinx.coroutines.Dispatchers;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@Metadata(
mv = {1, 1, 16},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\u0010\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\u0002\n\u0002\b\u0004\u001a\u0006\u0010\u0000\u001a\u00020\u0001\u001a\u0011\u0010\u0002\u001a\u00020\u0003H\u0086@ø\u0001\u0000¢\u0006\u0002\u0010\u0004\u001a\u0006\u0010\u0005\u001a\u00020\u0003\u001a\u0011\u0010\u0006\u001a\u00020\u0003H\u0086@ø\u0001\u0000¢\u0006\u0002\u0010\u0004\u0082\u0002\u0004\n\u0002\b\u0019¨\u0006\u0007"},
d2 = {"blockingIOTask", "", "child", "", "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", "main", "parent", "kotlin-coroutines"}
)
public final class CoroutinesKt {
public static final void main() {
int $i$f$measureTimeMillis = false;
long start$iv = System.currentTimeMillis();
int var5 = false;
BuildersKt.runBlocking$default((CoroutineContext)null, (Function2)(new CoroutinesKt$main$time$1$1((Continuation)null)), 1, (Object)null);
long time = System.currentTimeMillis() - start$iv;
String var6 = "Completed in: " + time + " ms.";
boolean var7 = false;
System.out.print(var6);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
@Nullable
public static final Object parent(@NotNull Continuation $completion) {
Object $continuation;
label27: {
if ($completion instanceof <undefinedtype>) {
$continuation = (<undefinedtype>)$completion;
if ((((<undefinedtype>)$continuation).label & Integer.MIN_VALUE) != 0) {
((<undefinedtype>)$continuation).label -= Integer.MIN_VALUE;
break label27;
}
}
$continuation = new ContinuationImpl($completion) {
// $FF: synthetic field
Object result;
int label;
@Nullable
public final Object invokeSuspend(@NotNull Object $result) {
this.result = $result;
this.label |= Integer.MIN_VALUE;
return CoroutinesKt.parent(this);
}
};
}
Object $result = ((<undefinedtype>)$continuation).result;
Object var5 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
StringBuilder var10000;
Thread var10001;
String var1;
boolean var2;
switch(((<undefinedtype>)$continuation).label) {
case 0:
ResultKt.throwOnFailure($result);
var10000 = new StringBuilder();
var10001 = Thread.currentThread();
Intrinsics.checkExpressionValueIsNotNull(var10001, "Thread.currentThread()");
var1 = var10000.append(var10001.getName()).append(" Hello from parent suspend function!").toString();
var2 = false;
System.out.println(var1);
((<undefinedtype>)$continuation).label = 1;
if (DelayKt.delay(1000L, (Continuation)$continuation) == var5) {
return var5;
}
break;
case 1:
ResultKt.throwOnFailure($result);
break;
case 2:
ResultKt.throwOnFailure($result);
return Unit.INSTANCE;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
var10000 = new StringBuilder();
var10001 = Thread.currentThread();
Intrinsics.checkExpressionValueIsNotNull(var10001, "Thread.currentThread()");
var1 = var10000.append(var10001.getName()).append(" Going to call child suspend function!").toString();
var2 = false;
System.out.println(var1);
((<undefinedtype>)$continuation).label = 2;
if (child((Continuation)$continuation) == var5) {
return var5;
} else {
return Unit.INSTANCE;
}
}
@Nullable
public static final Object child(@NotNull Continuation $completion) {
Object $continuation;
label20: {
if ($completion instanceof <undefinedtype>) {
$continuation = (<undefinedtype>)$completion;
if ((((<undefinedtype>)$continuation).label & Integer.MIN_VALUE) != 0) {
((<undefinedtype>)$continuation).label -= Integer.MIN_VALUE;
break label20;
}
}
$continuation = new ContinuationImpl($completion) {
// $FF: synthetic field
Object result;
int label;
@Nullable
public final Object invokeSuspend(@NotNull Object $result) {
this.result = $result;
this.label |= Integer.MIN_VALUE;
return CoroutinesKt.child(this);
}
};
}
Object $result = ((<undefinedtype>)$continuation).result;
Object var6 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
String result;
StringBuilder var8;
Object var10000;
Thread var10001;
switch(((<undefinedtype>)$continuation).label) {
case 0:
ResultKt.throwOnFailure($result);
var8 = new StringBuilder();
var10001 = Thread.currentThread();
Intrinsics.checkExpressionValueIsNotNull(var10001, "Thread.currentThread()");
result = var8.append(var10001.getName()).append(" I'm a child and I'm going to do some IO blocking work!").toString();
boolean var2 = false;
System.out.println(result);
CoroutineContext var9 = (CoroutineContext)Dispatchers.getIO();
Function2 var10 = (Function2)(new Function2((Continuation)null) {
private CoroutineScope p$;
Object L$0;
Object L$1;
Object L$2;
Object L$3;
int label;
@Nullable
public final Object invokeSuspend(@NotNull Object $result) {
Object var10000;
StringBuilder var5;
Object var6;
label17: {
Object var7 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
CoroutineScope $this$withContext;
Deferred firstString;
Deferred secondString;
switch(this.label) {
case 0:
ResultKt.throwOnFailure($result);
$this$withContext = this.p$;
firstString = BuildersKt.async$default($this$withContext, (CoroutineContext)null, (CoroutineStart)null, (Function2)(new Function2((Continuation)null) {
private CoroutineScope p$;
int label;
@Nullable
public final Object invokeSuspend(@NotNull Object $result) {
Object var3 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch(this.label) {
case 0:
ResultKt.throwOnFailure($result);
CoroutineScope $this$async = this.p$;
return CoroutinesKt.blockingIOTask();
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
}
@NotNull
public final Continuation create(@Nullable Object value, @NotNull Continuation completion) {
Intrinsics.checkParameterIsNotNull(completion, "completion");
Function2 var3 = new <anonymous constructor>(completion);
var3.p$ = (CoroutineScope)value;
return var3;
}
public final Object invoke(Object var1, Object var2) {
return ((<undefinedtype>)this.create(var1, (Continuation)var2)).invokeSuspend(Unit.INSTANCE);
}
}), 3, (Object)null);
secondString = BuildersKt.async$default($this$withContext, (CoroutineContext)null, (CoroutineStart)null, (Function2)(new Function2((Continuation)null) {
private CoroutineScope p$;
int label;
@Nullable
public final Object invokeSuspend(@NotNull Object $result) {
Object var3 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch(this.label) {
case 0:
ResultKt.throwOnFailure($result);
CoroutineScope $this$async = this.p$;
return CoroutinesKt.blockingIOTask();
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
}
@NotNull
public final Continuation create(@Nullable Object value, @NotNull Continuation completion) {
Intrinsics.checkParameterIsNotNull(completion, "completion");
Function2 var3 = new <anonymous constructor>(completion);
var3.p$ = (CoroutineScope)value;
return var3;
}
public final Object invoke(Object var1, Object var2) {
return ((<undefinedtype>)this.create(var1, (Continuation)var2)).invokeSuspend(Unit.INSTANCE);
}
}), 3, (Object)null);
var5 = new StringBuilder();
this.L$0 = $this$withContext;
this.L$1 = firstString;
this.L$2 = secondString;
this.L$3 = var5;
this.label = 1;
var10000 = firstString.await(this);
if (var10000 == var7) {
return var7;
}
break;
case 1:
var5 = (StringBuilder)this.L$3;
secondString = (Deferred)this.L$2;
firstString = (Deferred)this.L$1;
$this$withContext = (CoroutineScope)this.L$0;
ResultKt.throwOnFailure($result);
var10000 = $result;
break;
case 2:
var5 = (StringBuilder)this.L$3;
secondString = (Deferred)this.L$2;
firstString = (Deferred)this.L$1;
$this$withContext = (CoroutineScope)this.L$0;
ResultKt.throwOnFailure($result);
var10000 = $result;
break label17;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
var6 = var10000;
var5 = var5.append((String)var6);
this.L$0 = $this$withContext;
this.L$1 = firstString;
this.L$2 = secondString;
this.L$3 = var5;
this.label = 2;
var10000 = secondString.await(this);
if (var10000 == var7) {
return var7;
}
}
var6 = var10000;
return var5.append((String)var6).toString();
}
@NotNull
public final Continuation create(@Nullable Object value, @NotNull Continuation completion) {
Intrinsics.checkParameterIsNotNull(completion, "completion");
Function2 var3 = new <anonymous constructor>(completion);
var3.p$ = (CoroutineScope)value;
return var3;
}
public final Object invoke(Object var1, Object var2) {
return ((<undefinedtype>)this.create(var1, (Continuation)var2)).invokeSuspend(Unit.INSTANCE);
}
});
((<undefinedtype>)$continuation).label = 1;
var10000 = BuildersKt.withContext(var9, var10, (Continuation)$continuation);
if (var10000 == var6) {
return var6;
}
break;
case 1:
ResultKt.throwOnFailure($result);
var10000 = $result;
break;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
result = (String)var10000;
var8 = new StringBuilder();
var10001 = Thread.currentThread();
Intrinsics.checkExpressionValueIsNotNull(var10001, "Thread.currentThread()");
String var7 = var8.append(var10001.getName()).append(" And here's expected result: ").append(result).append('.').toString();
boolean var3 = false;
System.out.println(var7);
return Unit.INSTANCE;
}
@NotNull
public static final String blockingIOTask() {
TimeUnit.MILLISECONDS.sleep(2000L);
StringBuilder var10000 = new StringBuilder();
Thread var10001 = Thread.currentThread();
Intrinsics.checkExpressionValueIsNotNull(var10001, "Thread.currentThread()");
return var10000.append(var10001.getName()).append(" Read data from disk").toString();
}
}
Coroutines
- https://medium.com/@elizarov/blocking-threads-suspending-coroutines-d33e11bf4761,
- https://medium.com/androiddevelopers/coroutines-on-android-part-i-getting-the-background-3e0e54d20bb,
- https://medium.com/androiddevelopers/coroutines-on-android-part-ii-getting-started-3bff117176dd,
- https://medium.com/androiddevelopers/coroutines-on-android-part-iii-real-work-2ba8a2ec2f45,
- https://medium.com/@patson.luk/learning-kotlin-coroutines-as-a-java-dev-part-i-a04029b6214b,
- https://medium.com/@patson.luk/learning-kotlin-coroutines-as-a-java-dev-part-ii-dfe0d468b65e,
- https://medium.com/@esocogmbh/coroutines-in-pure-java-65661a379c85.
Coroutines suspending state machines:
- https://labs.pedrofelix.org/guides/kotlin/coroutines/coroutines-and-state-machines,
- https://medium.com/google-developer-experts/coroutines-suspending-state-machines-36b189f8aa60.
Structured concurrency:
- https://www.youtube.com/watch?v=Mj5P47F6nJg,
- https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/,
- https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/,
- https://libdill.org/structured-concurrency.html.
Loom
- https://wiki.openjdk.java.net/display/loom/Main,
- https://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part1.html,
- https://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part2.html,
- https://renato.athaydes.com/posts/taking-loom-for-a-spin.html,
- https://blog.usejournal.com/project-loom-virtual-threads-in-java-371dccc88b0f.
thanks!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
main Hello from parent suspend function!
main Going to call child suspend function!
main I'm a child and I'm going to do some IO blocking work!
main And here's expected result: DefaultDispatcher-worker-3 Read data from diskDefaultDispatcher-worker-2 Read data from disk.
Completed in: 3228 ms.