Thread ?
์ค๋ ๋ ์์ฑ
์ฝํ๋ฆฐ์ ์ค๋ ๋ ์์ฑ ๊ณผ์ ์ ๋จ์ํํด์ ์ฝ๊ณ ๊ฐ๋จํ๊ฒ ์ค๋ ๋๋ฅผ ์์ฑํ ์ ์๋ค. ์ง๊ธ์ ๋จ์ผ ์ค๋ ๋๋ง์ผ๋ก๋ ์ถฉ๋ถํ์ง๋ง, ์ดํ ๊ณผ์ ์์๋ CPU ๋ฐ์ด๋์ I/O ๋ฐ์ด๋ ์์ ์ ๋ชจ๋ ํจ์จ์ ์ผ๋ก ์ํํ๊ธฐ ์ํด ์ค๋ ๋ ํ๋ ์์ฑํ ๊ฒ์ด๋ค.
CoroutineDispatcher
์ฝํ๋ฆฐ์์๋ ์ค๋ ๋์ ์ค๋ ๋ ํ์ ์ฝ๊ฒ ๋ง๋ค ์ ์์ง๋ง ์ง์ ์์ธ์คํ๊ฑฐ๋ ์ ์ดํ์ง ์๋๋ค๋ ์ ์ ์์์ผ ํ๋ค.
์ฌ๊ธฐ์์๋ ์ค๋ ๋๋ฅผ ํ๋๋ง ๊ฐ๋ CoroutineDispatcher๋ฅผ ์์ฑํ ๊ฒ์ด๋ฉฐ, ๊ฑฐ๊ธฐ์ ์ถ๊ฐํ๋ ๋ชจ๋ ์ฝ๋ฃจํด์ ๊ทธ ํน์ ์ค๋ ๋์์ ์คํ๋๋ค. ๊ทธ๋ ๊ฒ ํ๋ ค๋ฉด ๋จ ํ๋์ ์ค๋ ๋๋ง ๊ฐ๋ CoroutineDispatcher๋ฅผ ํ์ฅํ ThreadPoolDispatcher๋ฅผ ์์ฑํ๋ค.
fun main(args: Array<String>) = runBlocking {
val netDispatcher = newSingleThreadContext(name = "ServiceCall")
val task = GlobalScope.launch(netDispatcher) {
printCurrentThread()
}
task.join()
}๋์คํจ์ฒ์ ์ฝ๋ฃจํด ๋ถ์ด๊ธฐ
๋์คํจ์ฒ๊ฐ ๋ง๋ค์ด์ก๊ณ ์ด์ ์ด ๋์คํจ์ฒ๋ฅผ ์ฌ์ฉํ๋ ์ฝ๋ฃจํด์ ์์ํ ์ ์๋ค.
async ์ฝ๋ฃจํด ์์
๊ฒฐ๊ณผ ์ฒ๋ฆฌ๋ฅผ ์ํ ๋ชฉ์ ์ผ๋ก ์ฝ๋ฃจํด์ ์์ํ๋ค๋ฉด async()๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค. async()๋ ๋ํผ๋ ์ฝ๋ฃจํด ํ๋ ์์ํฌ์์ ์ ๊ณตํ๋ ์ทจ์ ๋ถ๊ฐ๋ฅํ ๋ ๋ธ๋กํน ํจ์ฒ(non-blocking cancellable future)๋ฅผ ์๋ฏธํ์ฌ, T๋ ๊ทธ ๊ฒฐ๊ณผ์ ์ ํ์ ๋ํ๋ธ๋ค.
fun main(args: Array<String>) = runBlocking {
val task = GlobalScope.async {
doSomething()
}
task.join()
println("Completed")
}
fun doSomething() {
throw UnsupportedOperationException("Can't do")
}์์ธ๋ฅผ ํตํด ์ ํ๋ฆฌ์ผ์ด์ ์คํ์ด ๋ฉ์ถ๊ณ ์์ธ ์คํ์ด ์ถ๋ ฅ๋๋ฉฐ ๋ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ข ๋ฃ๊ฐ ๋์ง ์๋๊ฑฐ๋ผ๊ณ ์๊ฐํ ์ ์๋ค. ๊ทธ๋ฌ๋ ์คํํด๋ณด๋ฉด ๋ก๊ทธ์ ์ถ๋ ฅ๋๋ ์์ธ ์คํ์ ์์ผ๋ฉฐ ์ ํ๋ฆฌ์ผ์ด์ ๋ ์ค๋จ๋์ง ์์๊ณ ์ข ๋ฃ ์ฝ๋๋ ์ฑ๊ณต์ ์ผ๋ก ์คํ๋ ๊ฒ์ผ๋ก ๋ํ๋๋ค.
async() ๋ธ๋ก ์์์ ๋ฐ์ํ๋ ์์ธ๋ ๊ทธ ๊ฒฐ๊ณผ์ ์ฒจ๋ถ๋๋๋ฐ, ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํด์ผ ์์ธ๋ฅผ ์ฐพ์ ์ ์๋ค. ์ด๋ฅผ ์ํด์ isCancelled์ getCancellationException() ๋ฉ์๋๋ฅผ ํจ๊ป ์ฌ์ฉํด ์์ ํ๊ฒ ์์ธ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค.
if (task.isCancelled) {
val exception = task.getCancellationException()
println("Error with message: ${exception.cause}")
} else {
println("Success")
}์์ธ๋ฅผ ์ ํํ๊ธฐ ์ํด์ ๋ํผ๋์์ await()์ ํธ์ถํ ์ ์๋ค.
fun main(args: Array<String>) = runBlocking {
val task = GlobalScope.async {
doSomething()
}
// This code will have the exception be propagated
task.await()
println("Success")
}๊ทธ๋ฌ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋น์ ์์ ์ผ๋ก ์ค๋จ๋๋ค.
await()๋ฅผ ํธ์ถํด์ ์ค๋จ๋๋๋ฐ ์ด ๊ฒฝ์ฐ๊ฐ ์์ธ๋ฅผ ๊ฐ์ธ์ง ์๊ณ ์ ํํ๋ ๊ฐ์ธ์ง ์์ ๋ํผ๋(unwrapping deferred)๋ค.
join()์ผ๋ก ๋๊ธฐํ ํ ๊ฒ์ฆํ๊ณ ์ด๋ค ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒ๊ณผ await()๋ฅผ ์ง์ ํธ์ถํ๋ ๋ฐฉ์์ ์ฃผ์ ์ฐจ์ด๋ join()์ ์์ธ๋ฅผ ์ ํํ์ง ์๊ณ ์ฒ๋ฆฌํ๋ ๋ฐ๋ฉด, await()๋ ๋จ์ง ํธ์ถํ๋ ๊ฒ๋ง์ผ๋ก ์์ธ๊ฐ ์ ํ๋๋ค๋ ์ ์ด๋ค.
launch ์ฝ๋ฃจํด ์์
๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ์ง ์๋ ์ฝ๋ฃจํด์ ์์ํ๋ ค๋ฉด launch()๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค. launch()๋ ์ฐ์ฐ์ด ์คํจํ ๊ฒฝ์ฐ์๋ง ํต๋ณด ๋ฐ๊ธฐ๋ฅผ ์ํ๋ fire-and-forget ์๋๋ฆฌ์ค๋ฅผ ์ํด ์ค๊ณ๋์ผ๋ฉฐ, ํ์ํ ๋ ์ทจ์ํ ์ ์๋ ํจ์๋ ํจ๊ป ์ ๊ณต๋๋ค.
fun main(args: Array<String>) = runBlocking {
val task = GlobalScope.launch {
doSomething()
}
// This code will have the exception be propagated
task.join()
println("Success")
}์์ํ ๋๋ก ์์ธ๊ฐ ์คํ์ ์ถ๋ ฅ๋์ง๋ง ์คํ์ด ์ค๋จ๋์ง ์์๊ณ , ์ ํ๋ฆฌ์ผ์ด์ ์ main()์ ์คํ์ ์๋ฃํ๋ค๋ ๊ฒ์ ์ ์ ์๋ค.
์ฝ๋ฃจํด์ ์์ํ ๋ ํน์ ๋์คํจ์ฒ ์ฌ์ฉํ๊ธฐ
์ง๊ธ๊น์ง๋ ๊ธฐ๋ณธ ๋์คํจ์ฒ๋ฅผ ์ฌ์ฉํ์ง๋ง ๋ค์๊ณผ ๊ฐ์ด ํน์ ์ฝ๋ฃจํด ๋์คํจ์ฒ๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
fun main(args: Array<String>) = runBlocking {
val dispatcher = newSingleThreadContext(name = "ServiceCall")
val task = GlobalScope.launch(dispatcher) {
doSomething()
}
// This code will have the exception be propagated
task.join()
println("Success")
}์์ฝ
๋คํธ์ํฌ ์์ฒญ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋์์ ์ํํด์ผ ํ๋ค. ์ ๋ฐ์ดํธ๋๋ ๋ทฐ๋ฅผ ์ํ ์ ๋ณด๋ UI ์ค๋ ๋๋ก ์ ๋ฌํด์ผ ํ๋ค.
CoroutineDispatcher๋ ์ฝ๋ฃจํด์ ํน์ ์ค๋ ๋ ๋๋ ์ค๋ ๋ ๊ทธ๋ฃน์์ ์คํํ๋๋ก ํ ์ ์๋ค.
ํ๋ ์ด์์ ์ฝ๋ฃจํด์ launch ๋๋ async๋ก ์ค๋ ๋์์ ์คํํ ์ ์๋ค.
launch๋ ํ์ด์ด์คํฌ๊ฐฏ(fire-and-forget_์ ๊ฐ์ ์๋๋ฆฌ์ค์์ ์ฌ์ฉ๋ผ์ผ ํ๋๋ฐ, ์ฝ๋ฃจํด์ด ๋ฌด์ธ๊ฐ๋ฅผ ๋ฐํํ ๊ฒ์ ์์ํ์ง ์๋ ๊ฒฝ์ฐ๋ฅผ ๋งํ๋ค.
๋์ ์ฝ๋๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์๋ ์ฌ๋ฌ ๊ฐ์ง๊ฐ ์์ง๋ง, ๋ช ํํ๊ณ ์์ ํ๋ฉฐ ์ผ๊ด์ฑ ์๊ฒ ์ฝํ๋ฆฐ์ ์ ์ฐ์ฑ์ ์ต๋ํ ํ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ดํดํ๋ ๊ฒ์ด ์ค์ํ๋ค.
Last updated