개발

coroutine - launch, async, CoroutineContext

kwony 2023. 2. 28. 20:00

launch, async

 

coroutine을 시작하는 방법은 launch, async가 있다. launch는 결과값을 반환하지 않고 async는 await를 이용해서 결과값을 반환할 수 있다.

 

fun main() {
    ThreadTest().runCoroutine()
}

class ThreadTest {
    fun runCoroutine() = runBlocking {
        val jobs = ArrayList<Deferred<Int>>()

        (1..5).map { number ->
            val job = async {
                delay((Math.random() * 1000).toLong())
                println("${Thread.currentThread().name} done, number: $number")
                increaseCounter()
                return@async number
            }

            jobs.add(job)
        }

        jobs.forEach {
            println("result: ${it.await()}")
        }
    }
}
-------------------------------------------------------------------------
main done, number: 3
main done, number: 1
result: 1
main done, number: 5
main done, number: 2
result: 2
result: 3
main done, number: 4
result: 4
result: 5

 

코드에서 async 를 사용한 코루틴은 number 값을 리턴하도록 했고 jobs 리스트에서 그 값을 출력하도록 했다. 그 결과 1 부터 5까지 출력되는 것을 확인 할 수 있다.

 

fun main() {
    ThreadTest().runCoroutine()
}

class ThreadTest {
    fun runCoroutine() = runBlocking {
        val jobs = ArrayList<Job>()

        (1..5).map { number ->
            val job = launch {
                delay((Math.random() * 1000).toLong())
                println("${Thread.currentThread().name} done, number: $number")
                increaseCounter()
            }
            jobs.add(job)
        }

        jobs.forEach {
            it.start()
        }
    }
}
-------------------------------------------------------------------------
main done, number: 4
main done, number: 3
main done, number: 1
main done, number: 2
main done, number: 5

 

이번에는 async 대신 launch를 사용했다. launch로 코루틴을 선언하면 리턴값으로 Job을 받는다. jobs 변수에서 job 별로 start() 함수를 호출해 실행하도록 했더니 결과가 병렬적으로 처리되는 것을 확인 할 수 있었다.

 

CoroutineContext

 

그런데 출력 결과에서 신기한 점이 있다. 작업을 처리하는 쓰레드 이름이 모두 main으로 출력된 것이다. 코루틴을 실행할 때 CoroutineContext 를 정해주면 코루틴을 실행할 쓰레드를 지정할 수 있다. 코루틴 디스패쳐는 코루틴 작업을 특정 쓰레드 풀에 위임하고 실행한다. 작업에 따라서 쓰레드를 다르게 가져갈 수 있다.

 

fun main() {
    ThreadTest().runCoroutine2()
}

class ThreadTest {
    fun runCoroutine2() = runBlocking {
        launch {
            println("thread ${Thread.currentThread().name}")
        }
        launch(Dispatchers.Unconfined) {
            println("thread ${Thread.currentThread().name}")
        }
        launch(Dispatchers.Default) {
            println("thread ${Thread.currentThread().name}")
        }
        launch(newSingleThreadContext("MyOwnThread")) { 
            println("thread ${Thread.currentThread().name}")
        }
    }
}
-------------------------------------------------------------------------

thread main
thread DefaultDispatcher-worker-1
thread main
thread MyOwnThread

 

launch에 CoroutineContext 옵션을 넣어서 코루틴을 실행하는 쓰레드를 변경할 수 있다. 그 결과 출력된 쓰레드 이름이 다른것을 확인할 수 있다.