먼저 매우 간단한 kotlin 코루틴 코드를 살펴보겠습니다.
fun test4() {
GlobalScope.launch {
println("准备执行")
val value = async {
println("执行异步")
1024
}.await()
println("执行完毕:${value}")
}
}
중간에 비동기 실행 기간이 있으며 코드는 다음 작업을 계속 실행하기 전에 이 비동기 실행이 완료될 때까지 기다려야 합니다. 이제 이를 Java로 구현하고 두 개의 Runnable을 사용하여 시뮬레이션해 보겠습니다.
private static final Object COROUTINE_SUSPEND = "suspend";
class MyRunnable implements Runnable {
int label = 0;
@Override
public void run() {
invoke(null);
}
// 这段invoke代码就是上面那段了
public void invoke(Object result) {
Object value = COROUTINE_SUSPEND;
checkException(result);
switch (label) {
case 0:
println("准备执行");
value = async(this);
label = 1;
if (value == COROUTINE_SUSPEND) {
return;
}
break;
case 1:
value = result;
break;
}
int num = (int) value;
println("执行完毕:" + num);
}
};
class AsyncRunnable implements Runnable {
boolean isCompleted;
MyRunnable otherRunnable;
public Object myAsync(MyRunnable runnable) {
otherRunnable = runnable;
executors.submit(this);
return COROUTINE_SUSPEND;
}
@Override
public void run() {
invoke(null);
}
private void invoke(Object result) {
checkException(result);
println("执行异步");
int value = 1024;
isCompleted = true;
otherRunnable.invoke(value);
}
}
private Object async(MyRunnable myRunnable) {
AsyncRunnable asyncRunnable = new AsyncRunnable();
return asyncRunnable.myAsync(myRunnable);
}
사실 아주 간단합니다. 코루틴의 핵심은 함수나 프로그램을 일시 중지했다가 일시 중지된 위치에서 다시 시작할 수 있으며, 이 일시 중지 및 복구는 " 먼저 함수로 돌아가서 다시 시작하는 것입니다. 비동기 완료 후 실행합니다. " , 내부 코드는 실행할 여러 섹션으로 나뉩니다.
지금 바로 다음 코드를 검토하세요. 두 가지 사항이 매우 중요합니다.
(1) MyRunnable은 코루틴의 구현에 따라 비동기 함수가 호출될 때 전달됩니다. 즉, 각 일시 중단 함수에는 숨겨진 매개변수 Continuation이 있습니다. 일반 CPS 변환(계속 통과 스타일). 이 경우 비동기 작업이 완료된 후 바로 지금 MyRunnable 매개 변수의 invoke 메서드를 호출하면 됩니다.
(2) 레이블 변수에 의존하여 실행 지점을 기록하면 다음에 다시 호출할 때 마지막으로 실행된 단계를 알 수 있습니다.분할된 위치는 일시 중단 함수를 호출하고 COROUTINE_SUSPEND 플래그를 반환하는 것입니다.
읽은 후 Kotlin 코드의 컴파일된 바이트 코드를 보면 어떻게 구현되어 있는지 확인할 수 있습니다. 더 일반적으로 이해하려면 숨겨진 연속을 콜백으로 생각할 수 있으며 이는 매우 일반적입니다. Kotlin은 이러한 콜백을 모두 저장하므로 이러한 콜백을 작성할 필요가 없으며 동기처럼 보이는 비동기 코드를 작성할 수 있습니다. 코드 는 ~와 마찬가지로.
그렇다면 매우 중요한 질문이 있는데요 사실 코드를 보면 쓰레드 풀을 사용하든 코틀린 코루틴을 사용하든 효율은 같습니다 그래서 코드의 단순함과 더불어 코틀린을 어떻게 사용하는지 코루틴의 장점을 반영하기 위해서는 ?
코루틴이든 스레드 풀이든 블로킹을 유발하는 IO 작업의 경우 스레드는 필연적으로 차단됩니다. 효율성을 향상시킬 수 있는 것은 원래 Java에서 스레드 블로킹을 유발하는 일부 동작에 대해 kotlin을 사용하는 것입니다 . 대신 코루틴 API를 사용하여 스레드 리소스 사용을 최대화합니다 .
예를 들어:
- Thread.sleep 대신 지연을 사용하십시오.
- BlockCollection 대신 채널을 사용하십시오.
- 스레드의 yield 및 join 대신 kotlin의 yield 및 join을 사용합니다.
- Java의 잠금 메커니즘을 코루틴의 Metux로 교체합니다.
Thread.sleep과 같은 메소드의 경우 스레드가 차단되면 스레드가 계속 작동할 수 없으며 작업이 많은 경우 새 스레드를 다시 시작하여 실행할 수만 있으며 스레드가 상대적으로 리소스 집약적인 프로세스라는 것은 모두 알고 있습니다. 많은 메커니즘이 있는데, 코루틴 API는 이러한 차단 방식을 교묘하게 피하고 타이머를 설정한 후 다시 실행하는 지연 방식과 같은 더 가벼운 작업으로 구현합니다. 암호.