๊นจ์•Œ ๊ฐœ๋… ๐Ÿ“‘/Kotlin

[Kotlin] Coroutines - Parallel Decomposition

interfacer_han 2024. 2. 17. 11:41

#1 ์ž‘์—…์˜ ์ฒ˜๋ฆฌ ๋ฐฉ์‹

#1-1 ๊ฐ€์ •

์œ„์™€ ๊ฐ™์€ ์ด 7๊ฐœ์˜ ์ž‘์—…์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค. ๊ฐ ์ž‘์—…์ด ์†Œ์š” ์‹œ๊ฐ„์€ 5, 10, 15, 10, 20, 25, 5๋‹ค.

 

#1-2 ์ „ํ†ต์ ์ธ ๋ฐฉ๋ฒ•

์ „ํ†ต์ ์ธ ๋ฐฉ๋ฒ•์€ ์„ ํ˜•์ (Serial)์œผ๋กœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

 

#1-3 ์ „ํ†ต์ ์ธ ๋ฐฉ๋ฒ•์˜ ๊ตฌํ˜„

import kotlinx.coroutines.*

data class Food(val name: String, val cookingTimeInSeconds: Long)

suspend fun cook(food: Food) {
    delay(1000 * food.cookingTimeInSeconds)
    println("${food.name} ์™„๋ฃŒ")
}

fun main() {
    val foods = arrayOf(
        Food("๊ตญ๋ฐฅ", 5),
        Food("๋งŒ๋‘", 10),
        Food("๋น„๋น”๋ฐฅ", 15),
        Food("ํ–„๋ฒ„๊ฑฐ", 10),
        Food("์น˜ํ‚จ", 20),
        Food("ํ”ผ์ž", 25),
        Food("์ƒŒ๋“œ์œ„์น˜", 5),
    )

    val startTime = System.currentTimeMillis()

    runBlocking {
        for (food in foods) {
            cook(food)
        }
    }

    val endTime = System.currentTimeMillis()

    println("์ด ์†Œ์š” ์‹œ๊ฐ„: ${(endTime - startTime) / 1000.0}์ดˆ")
}

/* ์ถœ๋ ฅ ๊ฒฐ๊ณผ
๊ตญ๋ฐฅ ์™„๋ฃŒ
๋งŒ๋‘ ์™„๋ฃŒ
๋น„๋น”๋ฐฅ ์™„๋ฃŒ
ํ–„๋ฒ„๊ฑฐ ์™„๋ฃŒ
์น˜ํ‚จ ์™„๋ฃŒ
ํ”ผ์ž ์™„๋ฃŒ
์ƒŒ๋“œ์œ„์น˜ ์™„๋ฃŒ
์ด ์†Œ์š” ์‹œ๊ฐ„: 90.168์ดˆ
*/

์ „ํ†ต์ ์ธ ๋ฐฉ์‹์˜ ์ž‘์—… ์ฒ˜๋ฆฌ๋ฅผ ์ฝ”๋“œ๋กœ ๋‚˜ํƒ€๋‚ด๋ฉด ์œ„์™€ ๊ฐ™๋‹ค.

 

#1-4 Parallel Decomposition

Parallel Decomposition์€ ๋ฌธ์ œ๋ฅผ ์ž‘์€ ๋ถ€๋ถ„์œผ๋กœ ๋‚˜๋ˆ„์–ด ๋™์‹œ์— ์ฒ˜๋ฆฌํ•œ๋‹ค. 7๊ฐœ์˜ ์ž‘์—… ์ค‘ ๊ฐ€์žฅ ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…์ด ๊ณง ์ „์ฒด ์†Œ์š” ์‹œ๊ฐ„์ด ๋œ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ์ „์ฒด ์ž‘์—…์˜ ์‹œ๊ฐ„์„ ๋‹จ์ถ•์‹œํ‚จ๋‹ค. ๋‹ค์ˆ˜์˜ CPU ์ฝ”์–ด๋ฅผ ํšจ์œจ์ ์œผ๋กœ ํ™œ์šฉํ•ด ๋Œ€๊ทœ๋ชจ ๋ฌธ์ œ๋ฅผ ๋‚˜๋ˆ  ํ•ด๊ฒฐํ•œ ๊ฒƒ์ด๋‹ค. ์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” ์ฝ”๋ฃจํ‹ด์„ ์ด์šฉํ•ด ๋ฌธ์ œ๋ฅผ ๋ณ‘๋ ฌ๋กœ ๋‚˜์—ดํ•จ์œผ๋กœ์จ Parallel Decomposition์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

#1-5 Parallel Decomposition์˜ ๊ตฌํ˜„

import kotlinx.coroutines.*

data class Food(val name: String, val cookingTimeInSeconds: Long)

suspend fun cook(food: Food) {
    delay(1000 * food.cookingTimeInSeconds)
    println("${food.name} ์™„๋ฃŒ")
}

fun main() {
    val foods = arrayOf(
        Food("๊ตญ๋ฐฅ", 5),
        Food("๋งŒ๋‘", 10),
        Food("๋น„๋น”๋ฐฅ", 15),
        Food("ํ–„๋ฒ„๊ฑฐ", 10),
        Food("์น˜ํ‚จ", 20),
        Food("ํ”ผ์ž", 25),
        Food("์ƒŒ๋“œ์œ„์น˜", 5),
    )

    val startTime = System.currentTimeMillis()

    runBlocking {
        val cookingJobs: ArrayList<Job> = ArrayList()

        for (food in foods) {
            cookingJobs.add(launch {
                cook(food)
            })
        }
        
/* runBlocking์˜ ํŠน์„ฑ ๋•์— ์ƒ๋žต ๊ฐ€๋Šฅ. ์„ค๋ช… ์ฐธ์กฐ.
        for(cookingJob in cookingJobs) {
            cookingJob.join()
        }
*/
    }

    val endTime = System.currentTimeMillis()

    println("์ด ์†Œ์š” ์‹œ๊ฐ„: ${(endTime - startTime) / 1000.0}์ดˆ")
}

/* ์ถœ๋ ฅ ๊ฒฐ๊ณผ
๊ตญ๋ฐฅ ์™„๋ฃŒ
์ƒŒ๋“œ์œ„์น˜ ์™„๋ฃŒ
๋งŒ๋‘ ์™„๋ฃŒ
ํ–„๋ฒ„๊ฑฐ ์™„๋ฃŒ
๋น„๋น”๋ฐฅ ์™„๋ฃŒ
์น˜ํ‚จ ์™„๋ฃŒ
ํ”ผ์ž ์™„๋ฃŒ
์ด ์†Œ์š” ์‹œ๊ฐ„: 25.104์ดˆ
*/

Parallel Decomposition ๋ฐฉ์‹์˜ ์ž‘์—… ์ฒ˜๋ฆฌ๋ฅผ ์ฝ”๋“œ๋กœ ๋‚˜ํƒ€๋‚ด๋ฉด ์œ„์™€ ๊ฐ™๋‹ค. ์ฝ”๋ฃจํ‹ด์„ ์‚ฌ์šฉํ–ˆ๋‹ค. for๋ฌธ์˜ ๋ฐ˜๋ณต ํšŸ์ˆ˜๋งŒํผ ์ฝ”๋ฃจํ‹ด์ด ๋ณ‘๋ ฌ์ ์œผ๋กœ ์ˆ˜ํ–‰๋œ๋‹ค. ๊ฐ€์žฅ ํฐ Food.cookingTimeInSeconds๋Š” ๊ณง ๋ชจ๋“  ์ฝ”๋ฃจํ‹ด์ด ์™„๋ฃŒ๋˜๋Š” ์‹œ๊ฐ„์ด ๋œ๋‹ค. Job.join() ํ•จ์ˆ˜๋ฅผ ์ƒ๋žตํ•œ ์ด์œ ๋Š” runBlocking ํ•จ์ˆ˜๋Š” ์•ˆ์— ์žˆ๋Š” ๋ชจ๋“  ์ฝ”๋ฃจํ‹ด์ด ๋๋‚˜์•ผ ์ข…๋ฃŒ(์ด ๋งํฌ์˜ #3-2 ์ฐธ์กฐ)๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

#2 ์š”์•ฝ

๋ฌธ์ œ๋ฅผ ๋‚˜๋ˆ ์„œ ํ‘ธ๋Š” ๊ฑด ๋ˆ„๊ตฌ๋‚˜ ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ, ๋‚˜๋ˆˆ ๊ฑธ ๋ณ‘๋ ฌ์ ์œผ๋กœ ํ‘ผ๋‹ค๋ฉด ์–˜๊ธฐ๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค.