網站首頁 編程語言 正文
Kotlin 協程的優勢:
- 解決回調地獄的問題。
- 以同步的方式完成異步任務。
示例:
fun main() {
runBlocking {
val a = getA()
println(a)
val b = getB(a)
println(b)
val c = getC(b)
println(c)
}
}
suspend fun getA(): String {
withContext(Dispatchers.IO) {
delay(2000L)
}
return "A content"
}
suspend fun getB(a: String): String {
withContext(Dispatchers.IO) {
delay(2000L)
}
return "$a B content"
}
suspend fun getC(b: String): String {
withContext(Dispatchers.IO) {
delay(2000L)
}
return "$b C content"
}
輸出
A content
A content B content
A content B content C content
suspend關鍵字修飾的方法 就是 掛起函數。掛起函數具備掛起和恢復的能力。掛起就是將程序執行流程轉移到其他線程,主線程不阻塞。掛起函數的本質是Callback。
Kotlin編譯器檢測到suspend關鍵字修飾的函數,會將掛起函數轉換成帶有CallBack的函數。
suspend fun getA(): String {
withContext(Dispatchers.IO) {
delay(5000L)
println("now in A process:" + Thread.currentThread())
}
/**
* 這里的代碼涉及掛起函數中的操作。
*/
println("finish A process:" + Thread.currentThread())
return "A content"
}
將上述Kotlin代碼轉換成java代碼。
@Nullable
public static final Object getA(@NotNull Continuation var0) {
Object $continuation;
label20: {
if (var0 instanceof <undefinedtype>) {
$continuation = (<undefinedtype>)var0;
if ((((<undefinedtype>)$continuation).label & Integer.MIN_VALUE) != 0) {
((<undefinedtype>)$continuation).label -= Integer.MIN_VALUE;
break label20;
}
}
$continuation = new ContinuationImpl(var0) {
// $FF: synthetic field
Object result;
int label;
@Nullable
public final Object invokeSuspend(@NotNull Object $result) {
this.result = $result;
this.label |= Integer.MIN_VALUE;
return TestCoroutinue2Kt.getA(this);
}
};
}
Object $result = ((<undefinedtype>)$continuation).result;
Object var4 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch(((<undefinedtype>)$continuation).label) {
case 0:
ResultKt.throwOnFailure($result);
CoroutineContext var10000 = (CoroutineContext)Dispatchers.getIO();
Function2 var10001 = (Function2)(new Function2((Continuation)null) {
int label;
@Nullable
public final Object invokeSuspend(@NotNull Object $result) {
Object var3 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch(this.label) {
case 0:
ResultKt.throwOnFailure($result);
this.label = 1;
if (DelayKt.delay(5000L, this) == var3) {
return var3;
}
break;
case 1:
ResultKt.throwOnFailure($result);
break;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
String var2 = "now in A process:" + Thread.currentThread();
System.out.println(var2);
return Unit.INSTANCE;
}
@NotNull
public final Continuation create(@Nullable Object value, @NotNull Continuation completion) {
Intrinsics.checkNotNullParameter(completion, "completion");
Function2 var3 = new <anonymous constructor>(completion);
return var3;
}
public final Object invoke(Object var1, Object var2) {
return ((<undefinedtype>)this.create(var1, (Continuation)var2)).invokeSuspend(Unit.INSTANCE);
}
});
((<undefinedtype>)$continuation).label = 1;
if (BuildersKt.withContext(var10000, var10001, (Continuation)$continuation) == var4) {
return var4;
}
break;
case 1:
ResultKt.throwOnFailure($result);
break;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
String var1 = "finish A process:" + Thread.currentThread();
System.out.println(var1);
return "A content";
}
注意:runBlocking 的第二個參數 也是 傳入一個 suspend修飾的函數 即掛起函數。
public actual fun <T> runBlocking(context: CoroutineContext, block: suspend CoroutineScope.() -> T): T {
可以發現上面的Continuation 是一個帶有泛型參數的Callback,這里的轉換稱為CPS轉換,將原本的同步掛起函數轉換成CallBack異步代碼。
/**
* Interface representing a continuation after a suspension point that returns a value of type `T`.
*/
@SinceKotlin("1.3")
public interface Continuation<in T> {
/**
* The context of the coroutine that corresponds to this continuation.
*/
public val context: CoroutineContext
/**
* Resumes the execution of the corresponding coroutine passing a successful or failed [result] as the
* return value of the last suspension point.
*/
public fun resumeWith(result: Result<T>)
}
注意:掛起函數,只能在協程中被調用,或者被其他掛起函數調用。
為什么掛起函數可以調用掛起函數,而普通函數不能調用掛起函數?
fun main() {
doA() //這里會報錯
}
suspend fun doA() {
}
public static final void main() {
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
@Nullable
public static final Object doA(@NotNull Continuation $completion) {
return Unit.INSTANCE;
}
被調用的掛起函數需要傳入一個Continuation, 沒有被suspend修飾的函數是沒有Continuation參數的,所以沒法在普通函數中調用掛起函數,普通函數沒有Continuation。
掛起函數最終都是在協程中被調用,協程提供了掛起函數運行的環境。
原文鏈接:https://blog.csdn.net/zhangying1994/article/details/126691885
相關推薦
- 2022-04-16 python字符串不可變數據類型_python
- 2022-07-16 SpringMVC @Controller和@RequestMapping注解
- 2023-04-06 C++中的多態問題—理解虛函數表及多態實現原理_C 語言
- 2022-07-03 canvas文字居中;canvas畫布文字右對齊;canvas畫布文字左對齊;canvas文字自動換
- 2022-12-06 Python中八種數據導入方法總結_python
- 2022-07-02 react用axios的 get/post請求/獲取數據
- 2022-10-22 Python?修改CSV文件實例詳解_python
- 2021-12-12 C/C++?Qt?MdiArea?多窗體組件應用教程_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支