[요약]
이 장에서는 다른 플랫폼에서 코루틴을 사용하는 데 제한이 있다는 것에 대해 배웁니다.
코틀린 코루틴 개념을 다른 언어에서 사용할 수 있도록 변환하는 방법도 배우게 됩니다.
기본적인 방법: 중단 함수를 블로킹이나 콜백 함수로 변환
그 외: 플로우를 RxJava나 리액터 같은 라이브러리 객체로 변환, 다른 언어에서 사용 가능한 클래스로 래핑
다른 언어에서의 코루틴 사용법
언어에 따라 동시성에 접근하는 방식은 제각기 다르다.
자바: 스레드를 시작하고 블로킹하는 것이 일반적이다.
자바스크립트: 비동기 처리가 기본이며, 비동기 함수를 가지고 있다.
따라서 특정 플랫폼에서 동시성과 관련한 제한에는 어떤 것들이 있는지 알 필요가 있다.
이 장에서는 아래 두 가지에 대하여 알아보게 된다.
1) 코틀린의 특징 중 어떤 것들이 플랫폼에 종속적인지
2) API를 다른 언어에 노출하고 싶을 때 코틀린 코루틴을 플랫폼에 맞게 어떻게 변형시키는지
다른 플랫폼에서의 스레드 특징
자바스크립트
- 싱글스레드에서 작동하기 떄문에 sleep을 통해 일시 정지시키면 안됨
- 위와 같은 이유로 코틀린/자바스크립트에서 runBlocking을 지원하지 않음
- 코틀린/자바스크립트에서 테스트를 위해 runTest는 사용 가능
- Dispatchers.IO는 코틀린/JVM에 종속되어 코틀린/자바스크립트에서 사용 불가
(스레드 블로킹의 경우 JVM, 네티이브 API와 호환할 때만 일어나 자바스크립트에서는 문제가 되지 않음)
중단 함수를 비중단 함수로 변환하기
코틀린이 아닌 다른 언어에서 중단 함수를 호출할 수 없어서 다른 언어를 지원하는 라이브러리를 만들고 싶다면 대체할 수 있는 API를 명시해야 한다.
중단 함수를 블로킹 함수로 변환하기
코틀린/JVM 그리고 코틀린/네이티브에서 가장 쉬운 방법은 runBlocking을 사용해 중단 함수를 블로킹 함수로 변환하는 것이다.
책에서 좋은 방법은 아니라고 언급하고 있으나, 가장 쉬운 방법이라고 말하고 있다.
아래 코드 예시는 suspend가 붙은 중단 함수를 JVM 계열의 언어에서 사용 가능하도록 runBlocking을 추가해 변환한 것이다.
class DataService {
// 원본 중단 함수
suspend fun getUserData(userId: String): User {
delay(100)
return User(userId, "John")
}
// 자바나 다른 언어에서 사용할 수 있는 블로킹 함수로 변환
fun getUserDataBlocking(userId: String): User = runBlocking {
getUserData(userId) // 중단 함수를 블로킹으로 변환
}
}
fun main() {
val service = DataService()
// 자바에서도 호출 가능한 블로킹 함수
val user = service.getUserDataBlocking("123")
println(user)
}
추가적으로 함수에 알맞은 어노테이션을 붙이면 블로킹 함수를 암시적으로 생성하는 코틀린 플러그인이 있다.
> kotlin-jvm-blocking-bridge 가 그중 하나이다.
중단 함수를 콜백 함수로 변환하기
위에서 언급한 중단 함수를 블로킹 함수로 변환하는 것 외 중단 함수를 콜백 함수로 변환하는 것도 가능하다.
우선 코루틴 스코프를 정의해야하고, 그 스코프 내의 각 함수에서 코루틴을 시작해야한다.
아래의 예제는 책에 있는 것과 유사하게 동작하는 코드인데,
콜백 함수는 래퍼 함수가 종료되었을 때 성공을, 예외 시 실패를 나타내는 Result를 인자로 호출한다.
그리고 이 콜백 함수가 다시 특정 함수의 실행을 취소할 수 있는 Cancellable을 반환하도록 한다.
class DataService {
// 원본 중단 함수 (성공 했을 때)
suspend fun fetchUserData(userId: String): User {
delay(2000)
return User(userId, "John Doe", "john@email.com")
}
// 원본 중단 함수 (실패 했을 때)
suspend fun fetchUserDataWithError(userId: String): User {
delay(1500)
if (userId == "error") {
throw IllegalArgumentException("Invalid user ID: $userId")
}
return User(userId, "Jane Doe", "jane@email.com")
}
// 콜백 + Result + Cancellable 래퍼 함수
fun fetchUserDataWithCallback(
userId: String,
callback: (Result<User>) -> Unit
): Cancellable {
val job = CoroutineScope(Dispatchers.IO).launch {
try {
val user = fetchUserData(userId)
// 취소되지 않은 경우에만 성공 콜백 호출
if (isActive) {
callback(Result.Success(user))
}
} catch (e: Exception) {
// 취소되지 않은 경우에만 실패 콜백 호출
if (isActive) {
callback(Result.Failure(e))
}
}
}
return JobCancellable(job)
}
// 에러 처리가 포함된 콜백 래퍼 함수
fun fetchUserDataWithErrorCallback(
userId: String,
callback: (Result<User>) -> Unit
): Cancellable {
val job = CoroutineScope(Dispatchers.IO).launch {
try {
val user = fetchUserDataWithError(userId)
if (isActive) {
callback(Result.Success(user))
}
} catch (e: Exception) {
if (isActive) {
callback(Result.Failure(e))
}
}
}
return JobCancellable(job)
}
}
플랫폼 종속적인 옵션
플랫폼 마다 비동기 작업에 대한 독자적인 방법을 가지고 있다.
아래 코드는 자바스크립트의 Promise에 대한 예시인데, Promise는 자바스크립트에서 작업의 결과를 기다리는데 사용된다.
중단 함수를 시작하고 Promise를 반환값으로 노출하기 위해 promise 라는 코루틴 빌더를 사용한다.
// 코틀린/JVM에서는 runBlocking 사용 가능
fun jvmExample() {
runBlocking {
println("//")
delay(1000)
}
}
// 코틀린/JS에서는 runBlocking 불가능 - 대신 Promise 사용
fun jsExample(): Promise<Unit> {
return GlobalScope.promise {
println("//")
delay(1000)
}
}
플로우와 리액티브 스트림
간단한 변환 함수를 사용해서 Flow와 리액티브 스트림을 양방향으로 변환할 수 있다.
Flux, Observable 같은 리액티브 스트림의 모든 객체는 자바 표준 라이브러리를 통해 변환이 가능하다.
kotlinx-coroutines-reactive 라이브러리를 통해 asFlow 함수를 사용해 Flow로 변환할 수 있다.
더불어 kotlinx-coroutines-reactor로 Flow를 Flux로 변환하는 것도 가능하다.
마지막으로 kotlinx-coroutines-rx3을 통해 Flow를 Flowable 또는 Observable로 변환하는 것도 가능하다.
class DataStream {
// 코틀린 Flow
fun dataFlow(): Flow<String> = flow {
repeat(5) {
delay(1000)
emit("Data $it")
}
}
// RxJava Observable로 변환
fun dataObservable(): Observable<String> {
return dataFlow().asObservable()
}
// Reactor Flux로 변환
fun dataFlux(): Flux<String> {
return dataFlow().asFlux()
}
}
'Study OR Book > 코틀린 코루틴' 카테고리의 다른 글
[코틀린 코루틴] 24장 - 공유플로우와 상태플로우 (2) | 2025.07.14 |
---|---|
[코틀린 코루틴] 16장 - 채널 (0) | 2025.06.12 |
[코틀린 코루틴] 13장 - 코루틴 스코프 만들기 (1) | 2025.06.11 |
[코틀린 코루틴] 2장 시퀀스 빌더 (0) | 2025.05.20 |
[코틀린 코루틴] 1장 코틀린 코루틴을 배워야 하는 이유 (0) | 2025.05.20 |