선요약 : Deffered는 return값이 있어서 변수에 바로 값을 넣을수있다.
Job은 return값이 없어서 변수에 값을 넣으려면 Job 안에서 변수에 값을 넣어야한다.
Deffered = async의 반환값, 즉 async를 사용할때
Job = launch의 반환값, 즉 launch를 사용할때
Async와 Launch는 반환값 이외의 차이점은 없다.
Coroutines VS Async
async/await
kotlinx.coroutines.CoroutineScope.async
- async : 코드 블락을 정의
- await : 코드 블락의 종료를 대기
- async(/* Thread type 지정 */) : launch와 동일하며, 지정하지 않으면 상위 scope thread type을 따른다.
- 1개 이상의 coroutine 동기화가 필요한 경우 유용하게 사용할 수 있다.
async는 사실상 launch와 같은 일을 한다.
유일한 차이는 launch가 Job을 반환하는 반면 async는 Deffered를 반환한다는 점뿐이다.
Deffered는 Job을 상속한 클래스이기 때문에 launch 대신 async를 사용해도 항상 아무 문제가 없다.
실제로 두 함수의 구현을 보면 다음 코드와 같다.
Deffered vs Job
- Job은 아무 타입 파라미터가 없는데 Deffered 타입 파라미터가 있는 제네릭 타입
- Deffered 안에는 await() 함수가 정의되어 있다는 점
둘의 정의는 아래와 같이 요약하여 확인할 수 있다.
public interface Deferred<out T> : Job { ... }
public interface Job : CoroutineContext.Element { ... }
Defferred의 타입 파라미터는 코루틴이 계산을 하고 돌려주는 값의 타입이다.
Job은 Unit을 돌려주는 Defferred<Unit>이라고 생각할 수도 있을 것이다.
따라서 async는 코드 블록을 비동기로 실행할 수 있고,
async가 반환하는 Deffered의 await을 사용해서 코루틴이 결과 값을 내놓을 때까지 기다렸다가 결과 값을 얻어낼 수 있다.
제공하는 코루틴 컨텍스트에 따라 여러 스레드를 사용하거나 한 스레드 안에서 제어만 왔다 갔다 할 수도 있다
다음은 1부터 3까지 수를 더하는 과정을 async/await을 사용해 처리하는 모습을 보여준다.
fun sumAll() {
runBlocking {
val d1 = async { delay(1000L); 1 }
log("after async(dl)")
val d2 = async { delay(2000L); 2 }
log(" after async(d2)")
val d3 = async { delay(3000L); 3 }
log("after async(d3)")
log("1+2+3 = ${dl.await() + d2.await() + d3.await()}")
log ("after await all & add")
}
} // 5sec 136ms
fun now() = ZonedDateTime.now().toLocalTime().truncatedTo(ChronoUnit.SECONDS)
fun log(msg: String) = println("${now()}:${Thread.currentThread()}:${msg}")
22:45:25.208:Thread[main @coroutine#1,5,main]:after async(d1)
22:45:25.232:Thread[main @coroutine#1,5,main]: after async(d2)
22:45:25.232:Thread[main @coroutine#1,5,main]:after async(d3)
22:45:28.247:Thread[main @coroutine#1,5,main]:1+2+3 = 6
22:45:28.247:Thread[main @coroutine#1,5,main]:after await all & add
잘 살펴보면 d1, d2 ,d3를 하나하나 순서대로 실행하면 총 6초(6000밀리초) 이상이 걸리지만,
병렬 처리에서 이런 경우를 직렬화해 실행한다고 말한다
실제로 총 3초가 걸렸음을 알 수 있다.
또한 async로 코드를 실행하는 데는 시간이 거의 걸리지 않았다.
이 예제에서는 겨우 3개의 비동기 코드만을 실행했지만,
비동기 코드가 늘어날 수록 async/await을 사용한 비동기의 성능은 굉장히 뛰어날 것이다.
스레드를 여럿 사용하는 병렬 처리와 달리, 모든 async 함수들이 메인 스레드 안에서 실행됨을 볼 수 있다.
이 부분이 async/await과 스레드를 사용한 병렬 처리의 큰 차이이다.
실행하려는 작업이 시간이 얼마 걸리지 않거나 I/O에 의한 대기 시간이 크고,
CPU 코어 수가 작아 동시에 실행할 수 있는 스레드 개수가 한정된 경우에는
특히 코루틴과 일반 스레드를 사용한 비동기 처리 사이에 차이가 커진다.
참고로 launch를 사용한 코드는 아래와 같고, async와 동일한 효과를 볼 수 있다.
fun sumAllLaunch() = run {
var d1 = 0
var d2 = 0
var d3 = 0
runBlocking {
launch { delay(1000L); d1 = 1 }
log("after launch(dl)")
launch { delay(2000L); d2 = 2 }
log("after launch(d2)")
launch { delay(3000L); d3 = 3 }
log("after launch(d3)")
}
log("1+2+3 = ${d1 + d2 + d3}")
log("after await all & add")
}
22:45:28.263:Thread[main @coroutine#5,5,main]:after launch(d1)
22:45:28.264:Thread[main @coroutine#5,5,main]:after launch(d2)
22:45:28.265:Thread[main @coroutine#5,5,main]:after launch(d3)
22:45:31.267:Thread[main,5,main]:1+2+3 = 6
22:45:31.267:Thread[main,5,main]:after await all & add
출처 : https://gngsn.tistory.com/208
Kotlin, 코루틴 제대로 이해하기 - (2)
kotlin의 Coroutine을 이해하는 것이 해당 포스팅의 목표입니다. 🔗 Kotlin 시리즈 모아보기 사실, 순서대로라면 Class에 대한 내용을 다뤄야하는데, 추석이 끝나고 마음이 급해져서 코루틴이라도 파보
gngsn.tistory.com
'프로그래밍 > Kotlin' 카테고리의 다른 글
[Kotlin] Sealed Class (0) | 2024.08.20 |
---|---|
[Kotlin] Tesseract를 이용한 OCR 기능 추가 (0) | 2024.02.21 |
[Kotlin] 숫자 랜덤으로 출력 (0) | 2022.12.29 |
[Kotlin] ProgressBar 코드로 구현 (0) | 2022.12.15 |
[Kotlin] Java -> Kotlin Converting후 CustomDialog를 열때 Nullpointer Exception (0) | 2022.12.05 |
댓글