Coroutines는 Kotlin 1.1+에서 실험버전 입니다. 세부 사항은 아래를 참조하십시오 

일부 API는 네트워크 IO, 파일 IO, CPU 또는 GPU 집약적 인 작업 등과 같은 장기 실행 작업을 시작하고 호출자가 완료 될 때까지 차단하도록 요청합니다. 코 루틴은 스레드를 차단하지 않고 더 저렴하고 제어 가능한 작업 ( 코 루틴 중단) 으로 바꾸는 방법을 제공합니다 .

코루틴은 라이브러리에 합병증을 넣어 비동기 프로그래밍을 단순화합니다. 프로그램의 논리는 코 루틴 (coroutine)에서 순차적으로 표현 될 수 있으며 기본 라이브러리는 비동기를 파악할 것입니다. 라이브러리는 사용자 코드의 관련 부분을 콜백으로 래핑하고, 관련 이벤트를 구독하고, 다른 스레드 (또는 다른 시스템)에서 실행을 예약 할 수 있으며 코드는 순차적으로 실행되는 것처럼 간단합니다.

다른 언어에서 사용할 수있는 많은 비동기 메커니즘은 Kotlin 동시 루틴을 사용하여 라이브러리로 구현할 수 있습니다. 여기에는 async/await C # 및 ECMAScript를,에서 채널 및 select이동에서, 그리고 발전기 /yield C # 및 파이썬에서. 그러한 구조를 제공하는 라이브러리에 대해서는 아래 설명을 참조하십시오 .

블로킹 VS 연기

기본적으로 coroutine은 스레드 를 차단 하지 않고 일시 중단 될 수있는 계산입니다 스레드를 차단하는 것은 상대적으로 적은 수의 스레드 만 유지할 수 있으므로 고부하 인 경우 특히 비용이 많이 듭니다. 따라서 하나를 차단하면 중요한 작업이 지연됩니다.

반면 코 루틴의 서스펜션은 거의 무료입니다. 컨텍스트 스위치 또는 OS의 다른 개입은 필요하지 않습니다. 또한 사용자 라이브러리에 의해 서스펜션을 제어 할 수 있습니다. 라이브러리 작성자는 서스펜션시 발생할 일을 결정하고 필요에 따라 최적화 / 로그 / 인터셉트를 결정할 수 있습니다.

또 다른 차이점은 coroutine은 무작위 지시에 의해 중단 될 수 없으며 , 특별히 표시된 기능에 대한 호출 인 소위 정지 점 에서만 중단된다는 것 입니다.

서스펜딩 함수

서스펜션은 suspend 라는 특별한 수식어를 붙인 함수를 호출할 때 발생한다:

suspend fun doSomething(foo: Foo): Bar {
    ...
}

이러한 함수를 호출하면 콜 루틴이 일시 중단 될 수 있기 때문에 이러한 함수를 서스펜딩 함수 라고 합니다 (라이브러리는 문제의 호출에 대한 결과가 이미 사용 가능한 경우 라이브러리를 일시 중단하지 않고 계속 진행할 수 있습니다). 서스펜딩 함수는 일반 함수와 동일한 방식으로 매개 변수 및 반환 값을 사용할 수 있지만 코루틴및 다른 서스펜딩 함수에서만 호출 할 수 있습니다. 사실 코 루틴을 시작하려면 최소한 하나의 일시 중지 기능이 있어야하며 일반적으로 익명입니다 (즉, 람다 일시 중지). 도서관 async()에서 가져온 간단한 함수를 예로 들어 보겠습니다 kotlinx.coroutines.

fun <T> async(block: suspend () -> T)

여기에 async()정규 함수 (정지 함수가 아님)이지만 block매개 변수에 suspend수정자를 가진 함수 유형이 suspend () -> T있습니다. 그래서, 우리가 람다를 건네면 async(), 그것은 람다를 정지시키는 것이고, 우리는 그것으로부터 정지 함수를 호출 할 수 있습니다 :

async {
    doSomething(foo)
    ...
}

참고 : 현재 일시 중단 함수 유형은 수퍼 유형으로 사용할 수 없으며 익명 일시 중단 기능은 현재 지원되지 않습니다.

유추를 계속하려면, 어떤 계산이 끝날 때까지 코 루틴을 정지시키고 그 결과를 반환 await()할 수있는 정지 함수 ( async {}블록 내에서 호출 가능 )가 될 수 있습니다 :

async {
    ...
    val result = computation.await()
    ...
}

실제 방법에 대한 자세한 내용은 async/await기능의 작동은 kotlinx.coroutines찾을 수 있습니다 여기에.

일시 중지 함수는 다음 await()과 doSomething()같은 정규 함수에서 호출 할 수 없습니다 main().

fun main(args: Array<String>) {
    doSomething() // ERROR: Suspending function called from a non-coroutine context 
}

또한 일시 중단 함수는 가상 일 수 있으며, 함수를 무시할 때 suspend수식어를 지정해야합니다.

interface Base {
    suspend fun foo()
}

class Derived: Base {
    override suspend fun foo() { ... }
}

@RestrictsSuspension 주석

확장 함수 (및 람다)는 suspend일반 함수와 마찬가지로 표시 할 수 있습니다. 이를 통해 사용자가 확장 할 수있는 DSL 및 기타 API를 만들 수 있습니다. 경우에 따라 라이브러리 작성자는 사용자 가 코 루틴을 일시 중단하는 새로운 방법 을 추가하지 못하도록해야합니다 .

이를 달성하기 위해 @RestrictsSuspension주석을 사용할 수 있습니다. 수신자 클래스 또는 인터페이스 R에 주석이 달린 경우 모든 일시 중단 확장 프로그램은 회원 R또는 다른 확장 프로그램에 위임 해야합니다. 확장 프로그램은 무한정 서로 위임 할 수 없으므로 (프로그램이 종료되지 않음) R라이브러리 작성자가 완전히 제어 할 수 있다는 호출 멤버를 통해 모든 일시 중단이 발생 합니다.

모든 서스펜션이 도서관에서 특별한 방식으로 처리 되는 드문 경우에 관련이 있습니다. 예를 들어, 아래 에서 buildSequence()설명 하는 함수를 통해 생성기를 구현할 때 우리는 coroutine에서 일시 중단 된 호출이 다른 함수 나 다른 함수를 호출 하지 않도록해야합니다. 이것은 왜 주석을 붙일 수 :yield()yieldAll()SequenceBuilder@RestrictsSuspension

@RestrictsSuspension
public abstract class SequenceBuilder<in T> {
    ...
}

Github 의 출처  확인하십시오 .

코 루틴의 내부 작용

우리는 여기에서 코 루틴이 어떻게 작동하는지에 대한 완전한 설명을하려고하지는 않지만, 무슨 일이 일어나고 있는지 거친 감각이 중요합니다.

코 루틴은 컴파일 기술을 통해 완벽하게 구현됩니다 (VM 또는 OS 측의 지원이 필요 없음). 코드 변환을 통해 일시 중지가 작동합니다. 기본적으로 모든 일시 중지 기능 (최적화가 적용될 수 있지만 여기서는 다루지 않습니다)은 상태가 호출 일시 중지에 해당하는 상태 시스템으로 변환됩니다. 일시 정지 직전에 다음 상태는 관련 로컬 변수와 함께 컴파일러 생성 클래스의 필드에 저장됩니다. 해당 코 루틴의 재개시 로컬 변수가 복원되고 상태 시스템은 일시 중단 직후 상태에서 진행됩니다.

일시 중지 된 코 루틴은 일시 중단 된 상태 및 로컬을 유지하는 개체로 저장되고 전달 될 수 있습니다. 이러한 객체의 유형이 Continuation여기에 설명 된 전체 코드 변환은 고전적인 연속 전달 스타일에 해당 합니다. 따라서 일시 중단 함수 Continuation는 후드 아래에 추가 매개 변수를 사용합니다 .

코 루틴의 작동 방식에 대한 자세한 내용은 이 디자인 문서 에서 확인할 수 있습니다 다른 언어 (예 : C # 또는 ECMAScript 2016)와 유사한 async / await에 대한 설명은 여기에서 관련이 있습니다. 구현하는 언어 기능이 Kotlin 코 루틴만큼 일반적이지는 않습니다.

코 루틴의 실험적 상태

코 루틴의 디자인은 실험적 입니다. 곧 출시 될 릴리스에서 변경 될 것입니다. Kotlin 1.1+에서 동시 루틴을 컴파일 할 때 기본적으로 경고가 표시됩니다. "coroutines"기능은 실험적 입니다. 경고를 제거하려면 옵트 인 플래그를 지정해야합니다 .

실험실 상태로 인해 표준 라이브러리의 코 루틴 관련 API가 kotlin.coroutines.experimental패키지 아래에 배치 됩니다. 디자인이 완료되고 실험 상태가 해제되면 최종 API가로 이동되고 kotlin.coroutines실험 패키지는 이전 버전과의 호환성을 위해 유지됩니다 (아마도 별도의 이슈로 남게됩니다).

중요 참고 사항 : 라이브러리 작성자는 동일한 규칙을 따르는 것이 좋습니다. com.example.experimental패키지에 "experimental"(예 :) 접미사를 추가하여 coroutine 기반 API를 노출 시키면 라이브러리가 바이너리 호환이 가능합니다. 최종 API가 출시되면 다음 단계를 따르십시오.

  • 모든 API를 com.example(실험적인 접미사없이) 복사하십시오.
  • 이전 버전과의 호환성을 위해 실험 패키지를 보관하십시오.

이렇게하면 사용자의 마이그레이션 문제가 최소화됩니다.

표준 API

코 루틴은 세 가지 주요 성분으로 나뉩니다 :

  • 언어 지원 (위에서 설명한대로 기능을 일시 중단합니다).
  • Kotlin 표준 라이브러리의 저수준 핵심 API;
  • 사용자 코드에서 직접 사용할 수있는 고급 API

낮은 수준의 API : kotlin.coroutines

하위 수준 API는 상대적으로 작으며 상위 수준 라이브러리를 만드는 용도 이외의 용도로 사용해서는 안됩니다. 이 패키지는 두 가지 주요 패키지로 구성됩니다.

이 API의 사용법에 대한 자세한 내용은 여기를 참조하십시오 .

의 발전기 API kotlin.coroutines

에있는 유일한 "응용 프로그램 수준"기능은 다음 kotlin.coroutines.experimental과 같습니다.

이들은 kotlin-stdlib서열과 관련되어 있기 때문에 안으로 배송됩니다 사실, 이러한 기능들은 (그리고 우리는 buildSequence()여기서 혼자만을 할 수 있습니다) 생성기를 구현 합니다 . 즉, 게으른 시퀀스를 저렴하게 구축 할 수있는 방법을 제공합니다.

대상 플랫폼 : kotlin v. 1.2.10 에서 실행되는 JVM

이것은 yield()함수 를 호출하여 피보나치 수를 연속적으로 산출하는 코 루틴 (coroutine)을 생성함으로써 게으르고 잠재적으로 무한한 피보나치 수열을 생성 합니다. 이러한 시퀀스를 반복 할 때 반복자의 모든 단계가 다음 번호를 생성하는 코 루틴의 다른 부분을 실행합니다. 그래서 우리는이 시퀀스에서 임의의 유한 숫자 목록을 취할 수 있습니다 (예 : fibonacciSeq.take(8).toList()결과) [1, 1, 2, 3, 5, 8, 13, 21]그리고 코 루틴은 충분히 실용적입니다.

이러한 시퀀스의 실제 게으름을 보여주기 위해 buildSequence()다음 호출에 디버그 출력을 인쇄 해 보겠습니다 .

대상 플랫폼 : kotlin v. 1.2.10 에서 실행되는 JVM

위의 코드를 실행하면 처음 세 요소가 인쇄됩니다. 숫자는 STEP생성 루프에서 s로 인터리브됩니다 이것은 계산이 실제로 게으른 것을 의미합니다. 인쇄하려면 1처음까지만 실행 하고 길을 따라 yield(i)인쇄 START하십시오. 그런 다음 인쇄 2하려면 다음으로 진행해야하며 yield(i)인쇄 STEP됩니다. 같아 3시퀀스의 다른 요소를 결코 요구하지 않았기 때문에 다음은 STEP결코 인쇄되지 않습니다 (뿐만 아니라 END).

한 번에 값의 컬렉션 (또는 시퀀스)을 생성하려면 yieldAll()함수를 사용할 수 있습니다.

대상 플랫폼 : kotlin v. 1.2.10 에서 실행되는 JVM

이는 buildIterator()유사하게 작동 buildSequence()하지만 느린 반복기를 반환합니다.

위에 설명  주석 buildSequence()을 포함하는 SequenceBuilder클래스에 일시 중단 확장을 작성 하여 사용자 정의 논리를 추가 할 수 있습니다 .@RestrictsSuspension

대상 플랫폼 : kotlin v. 1.2.10 에서 실행되는 JVM

기타 높은 수준의 API : kotlinx.coroutines

Coroutine과 관련된 핵심 API 만 Kotlin 표준 라이브러리에서 사용할 수 있습니다. 이것은 주로 모든 코 루틴 기반 라이브러리가 사용할 핵심 기본 요소와 인터페이스로 구성됩니다.

코 루틴을 기반으로하는 대부분의 응용 프로그램 수준 API는 별도의 라이브러리로 릴리스됩니다 kotlinx.coroutines이 라이브러리는

  • 플랫폼 독립적 인 비동기 프로그래밍 kotlinx-coroutines-core:
    • 이 모듈은 Go와 유사한 채널을 지원 select하고 다른 편리한 프리미티브를 포함하고 있습니다.
    • 이 라이브러리에 대한 포괄적 인 안내서가 여기에 있습니다 .
  • CompletableFutureJDK 8 에 기반한 API kotlinx-coroutines-jdk8;
  • JDK 7 이상의 API를 기반으로하는 비 차단 IO (NIO) : kotlinx-coroutines-nio;
  • Swing ( kotlinx-coroutines-swing) 및 JavaFx ( kotlinx-coroutines-javafx) 지원;
  • RxJava 지원 : kotlinx-coroutines-rx.

이 라이브러리는 공통 작업을 쉽게 수행 할 수있는 편리한 API와 함께 코 루틴 기반 라이브러리를 작성하는 방법의 예를 제공합니다.