Coroutine
[Coroutine Basics 3] Coroutine Builder and Job
xiaolin219
2024. 1. 18. 17:39
- Coroutine Builder : 코루틴을 만드는 함수
1. runBlocking
- runBloking으로 인해 만들어진 코루틴과, 그 내부에 있는 코로틴이 모두 완료 될 때까지 스레드 블락
- 프로그램 최초 진입 지점인 메인함수, 혹은 테스트 코드 시작 시에만 사용 권장
- 반환값 없음
2. launch
launch의 반환 값은 Job 객체이다
Job 객체를 활용해 코루틴을 제어할 수 있다
start()
: launch{} 블록에서CoroutineStart.LAZY
옵션을 사용 후 start()를 통해 동작cancel()
: 코루틴 취소join()
: 코루틴이 끝날때 까지 대기fun main(): Unit = runBlocking { val job1 = launch { delay(1_000) printWithThread("Job 1") } job1.join() // 해당 함수의 유무에 따라 val job2 = launch { delay(1_000) printWithThread("Job 2") } }
join() 없을 때 join() 있을 때 실행시간 1.1초 실행시간 2초
3. async
launch와 async
launch와 유사하나, 실행결과를 반환 받을 수 있다
fun main(): Unit = runBlocking { val job = async { 3+5 } val eight = job.await() }
async()는 Defferd 객체를 반환한다
launch의 반환 타입인 Job과 Deffered는 둘 다 인터페이스이다. 아래 두번째 이미지와 같이 Deffered는 Job을 상속받고 있다.
따라서 launch에 기재해둔 함수를 동일하게 사용할 수 있으나,
await()
함수를 통해 실행 결과 값 반환이 가능하다async를 활용해 여러 api를 동시에 호출하여 소요시간을 최소화 할 수 있다
async 블록 내부 Deffered와 Job의 관계
async와 await
아래와 같이 async 블록을 통해 두개의 api를 호출하는 예시를 보자.
아래 코드에서 비동기로 각각 두개의 api가 호출됨으로 소요시간을 최소화 할 수 있다.
async()와 await() 함수 활용을 통해 동기식으로 코드 작성이 가능하다 (callback x)
// apiCall1 : 1초 소요, apiCall2 : 1초 소요 가정 // api1, 2가 동시에 호출되 // 총 1.013 초 소요 fun main(): Unit = runBlocking { val time = measureTimeMillis { val job1 = async { apiCall1() } val job2 = async { apiCall2() } printWithThread(job1.await() + job2.await()) } } // 만약 apiCall2에서 apiCall1의 결과값이 필요한경우 // job1의 결과 도착 후 apiCall2 실행됨 // 총 약 2초 소요 suspend fun apiCall2(num: Int): Int { delay(1_000L) return num + 2 } fun main(): Unit = runBlocking { val time = measureTimeMillis { val job1 = async { apiCall1() } val job2 = async { apiCall2(job1.await()) } // job1의 결과 도착 후 apiCall2 실행 printWithThread(job2.await()) } } // Lazy 옵션을 사용했는데, start()를 명시적으로 사용하지 않는다면 // await()를 만났을 때 코드가 실행되기 때문에 두개의 api가 동시에 호출되지 않음 // 총 약 2초 소요 fun main(): Unit = runBlocking { val time = measureTimeMillis { val job1 = async(start = CoroutineStart.LAZY) { apiCall1() } val job2 = async(start = CoroutineStart.LAZY) { apiCall2() } printWithThread(job1.await() + job2.await()) } } // start를 명시적으로 사용했기에 동시 호출 // 총 약 1초 소요 fun main(): Unit = runBlocking { val time = measureTimeMillis { val job1 = async(start = CoroutineStart.LAZY) { apiCall1() } val job2 = async(start = CoroutineStart.LAZY) { apiCall2() } job1.start() job2.start() printWithThread(job1.await() + job2.await()) } }