๐ก ์ฝ๋ฃจํด์์ ๋ฐ์ํ ์ ์๋ ๊ณต์ ์ํ๋ก ์ธํ ๋ฌธ์ ๋ฅผ ํ์ธํ๊ณ , ์ด๋ฅผ ๋๊ธฐํ ๋ธ๋กํน์ ํตํด ์ด๋ป๊ฒ ํด๊ฒฐํ ์ ์๋์ง ํ์ตํ์์ต๋๋ค.
๊ณต์ ์ํ๋ก ์ธํ ๋ฌธ์
class UserDowloader(
private val api : NetworkService
) {
private val users = mutableListOf<User>()
fun downloaded(): List<User> = users.toList()
suspend fun fetchUser(id: Int) {
val newUser = api.fetchUser(id)
users.add(newUser)
}
}
- ์ ์ฝ๋๋ ๋์ ์ฌ์ฉ์ ๋ํ ๋๋น๊ฐ ๋์ด ์์ง ์์ต๋๋ค.
- fetchUser ํธ์ถ์ users๋ฅผ ๋ณ๊ฒฝํ๋๋ฐ, ์ด ๊ฒฝ์ฐ ๊ฐ์ ์๊ฐ์ ํด๋น ํจ์๊ฐ ํ ๊ฐ ์ค๋ ๋์์ ์์ํ ๊ฒฝ์ฐ์๋ง ์ ์์ ์ผ๋ก ์๋ํฉ๋๋ค.
- ๋ง์ฝ ๋์์ ๋ฆฌ์คํธ๋ฅผ ๋ณ๊ฒฝํ๋ฉด ์ถฉ๋์ด ๋ฐ์ํ ์ ์์ผ๋ฉฐ, ์๋์ ๊ฐ์ ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์์ต๋๋ค.
- ๊ฐ์ ๊ฐ์ฒด์ ๋ํ์ฌ 1_000_000๋ฒ ์คํํ ๊ฒฝ์ฐ ์ค์ ๋ก ๊ธฐ๋ํ๋ ์๋ณด๋ค ์์ ํธ์ถ์ด ๋ฐ์ํ๋ฉฐ, ์์ธ๊ฐ ์๊ธธ ์๋ ์์ต๋๋ค.
repeat(1_000_000) {
launch {
downloader.fetchUser(it)
}
}
๋๊ธฐํ ๋ธ๋กํน
- ๊ณต์ ์ํ๋ก ์ธํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ์๋ฐ์์๋ synchronized ๋ธ๋ก์ด๋ ๋๊ธฐํ๋ ์ปฌ๋ ์ ์ ์ฌ์ฉํฉ๋๋ค.
synchronized(lock) { // ์ค๋ ๋๋ฅผ ๋ธ๋กํนํฉ๋๋ค
counter++
}
- ํ์ง๋ง ์ ๋ฐฉ์์ ์๋์ ๊ฐ์ ๋ฌธ์ ์ ์ด ์์ต๋๋ค.
- synchronized ๋ด๋ถ์์ ์ค๋จ ํจ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- synchronized ๋ธ๋ก์์ ์ฝ๋ฃจํด์ด ์๊ธฐ ์ฐจ๋ก๋ฅผ ๊ธฐ๋ค๋ฆด ๋ ์ค๋ ๋๋ฅผ ๋ธ๋กํนํฉ๋๋ค.
- ๋์คํจ์ฒ์ ์๋ฆฌ๋ฅผ ์๊ฐํ๋ค๋ฉด ์ฝ๋ฃจํด์ด ์ค๋ ๋๋ฅผ ๋ธ๋กํนํ๋ ๊ฒ์ ์ง์ํด์ผ ํฉ๋๋ค.
- ๋ฉ์ธ ์ค๋ ๋๋ฅผ ๋ธ๋กํนํ๊ฑฐ๋ ์ ํ ๋ ์์ ์ค๋ ๋๋ง ๊ฐ์ง๊ณ ์๋ ๊ฒ์ ์ข์ง ์์ต๋๋ค !!
- ์ค๋ ๋๋ฅผ ๋ญ๋นํ์ง ์๊ณ , ์ฝ๋ฃจํด์ ํนํ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
์์์ฑ
- ์๋ฐ์์๋ ์์๊ฐ์ ํ์ฉํ ์ฐ์ฐ์ ์ฌ์ฉํ๋ฉด (์์์ฑ ์ฐ์ฐ) ๋ฝ ์์ด ๋ก์ฐ ๋ ๋ฒจ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
private var counter = AtomicInteger() //์์์ฑ ์ฐ์ฐ
fun main() = runBlocking {
massiveRun {
counter.incrementAndGet()
}
}
- ๋ฌผ๋ก ํ๋์ ์ฐ์ฐ์์ ์์์ฑ์ ๊ฐ์ง๊ณ ์๋ค๊ณ ํด์ ์ ์ฒด ์ฐ์ฐ์์ ์์์ฑ์ด ๋ณด์ฅ๋๋ ๊ฒ์ ์๋๋๋ค.
- ์ด๋ ํ๋์ ํ๋ฆฌ๋ฏธํฐ๋ธ ๋ณ์ ๋๋ ํ๋์ ๋ํผ๋ฐ์ค์ ์์ ์ ๋ณด์ฅํ๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
์ฑ๊ธ์ค๋ ๋๋ก ์ ํ๋ ๋์คํจ์ฒ
- ๊ณต์ ์ํ๋ก ์ธํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ๋ณ๋ ฌ์ฑ์ ํ๋์ ์ค๋ ๋๋ก ์ ํํ๋ ๋์คํจ์ฒ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
val dispatcher = Dispatchers.IO
.limitedParallelism(1)
var counter = 0
fun main() = runBlocking {
massiveRun {
withContext(dispatcher){
counter++
}
}
}
- ์ฑ๊ธ ์ค๋ ๋๋ฅผ ๋์คํจ์ฒ๋ก ์ ํํ๋ ๋ฐฉ๋ฒ์๋ ๋๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
- ์ฒซ๋ฒ์งธ๋ ์์ฒ๋ผ withContect๋ก ์ ์ฒด ํจ์๋ฅผ ๋ํํ๋ ์ฝ์ค ๊ทธ๋ ์ธ๋ ์ค๋ ๋ ํ์ ์
๋๋ค.
- ์ฌ์ฉํ๊ธฐ ์ฌ์ฐ๋ฉฐ ์ถฉ๋์ ๋ฐฉ์งํ ์ ์์ง๋ง, ํจ์ ์ ์ฒด์์ ๋ฉํฐ์ค๋ ๋ฉ์ ์ด์ ์ ๋๋ฆฌ์ง ๋ชปํ๋ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
- ๋๋ฒ์งธ ๋ฐฉ๋ฒ์ ํ์ธ ๊ทธ๋ ์ธ๋ ์ค๋ ๋ ํ์ ์
๋๋ค.
- ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ ๊ตฌ๋ฌธ๋ค๋ง ๋ํํ๋ฉฐ, ๋ฒ๊ฑฐ๋กญ์ง๋ง CPU ์ง์ฝ์ ์ธ ๊ฒฝ์ฐ์ ๋ ๋์ ์ฑ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- ์ฒซ๋ฒ์งธ๋ ์์ฒ๋ผ withContect๋ก ์ ์ฒด ํจ์๋ฅผ ๋ํํ๋ ์ฝ์ค ๊ทธ๋ ์ธ๋ ์ค๋ ๋ ํ์ ์
๋๋ค.
val dispatcher = Dispatchers.IO
.limitedParallelism(1)
suspend fun downloaded(): List<User> =
withContext(dispatcher){
users.toList()
}
๋ฎคํ ์ค (Mutex)
- ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ๋ฐฉ์์ด๋ฉฐ, ๋จ ํ๋์ ์ด์ ๊ฐ ์๋ ๋ฐฉ์ด๋ผ๊ณ ํํํ ์ ์์ต๋๋ค.
- ์ฒซ ๋ฒ์งธ ์ฝ๋ฃจํด์ด lock์ ํธ์ถํ๋ฉด ์ด์ ๋ฅผ ๊ฐ์ง๊ณ ์ค๋จ ์์ด ์์ ์ ์ํํฉ๋๋ค.
- ๋๋ค๋ฅธ ์ฝ๋ฃจํด์ด lock์ ํธ์ถํ๋ฉด ์ฒซ ๋ฒ์งธ ์ฝ๋ฃจํด์ด unlock์ ํธ์ถํ ๋๊น์ง ์ค๋จ๋ฉ๋๋ค.
- ํ์ฅ์ค์ ์ด์ ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ์์ ๊ณผ ์ ์ฌ
- ์ด ์ํฉ์์ ๋ ๋ค๋ฅธ ์ฝ๋ฃจํด์ด lock์ ํธ์ถํ ๊ฒฝ์ฐ ์์ ์ ์ค๋จํ ๋ค์ ๋ ๋ฒ์งธ ์ฝ๋ฃจํด ๋ค์ ์์๋ก ํ์ ๋ค์ด๊ฐ๊ฒ ๋ฉ๋๋ค.
- ๋จ ํ๋์ ์ฝ๋ฃจํด๋ง์ด lock๊ณผ unlock ์ฌ์ด์ ์กด์ฌํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
suspend fun main() = coroutineScope {
repeat(5){
launch {
delayAndPrint()
}
}
}
val mutex = Mutex()
suspend fun delayAndPrint() {
mutex.lock()
delay(1000)
mutex.unlock()
}
- lock๊ณผ unlock์ ์ง์ ์ฌ์ฉํ๋ ๊ฒ์ ์์ธ๊ฐ ๋ฐ์ํ๊ฑฐ๋ ๋ฐํ์ด ๋น ๋ฅด๊ฒ ์ด๋ค์ง ๊ฒฝ์ฐ ์ํํ ์ํฉ์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
- ๋ค๋ฅธ ์ฝ๋ฃจํด์ด lock์ ํต๊ณผํ ์ ์๋ ๊ฒฝ์ฐ (์ด์ ๋ฅผ ๋๋ ค๋ฐ์ง ๋ชปํจ) ๋ฐ๋๋ฝ ์ํฉ์ด ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค.
- [๋ฐ๋๋ฝ] : ์์คํ ์์์ ๋ํ ์๊ตฌ๊ฐ ๋ค์ํจ ์ํ์ด๋ฉฐ, ์ ์ ํ๊ณ ์๋ ์์์ ์๋ก ๊ธฐ๋ค๋ฆฌ๋ ์ํฉ
- ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ lock์ผ๋ก ์์ํด finally ๋ธ๋ก์์ unlock์ ํธ์ถํ๋ withLock ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด ๋ธ๋ก ๋ด์์ ์ด๋ค ์์ธ๊ฐ ๋ฐ์ํ๋๋ผ๋ ์ฑ๊ณต์ ์ผ๋ก ํด๊ฒฐํ ์ ์์ต๋๋ค.
val mutex = Mutex()
var counter = 0
fun main() = runBlocking {
messiveRun {
mutex.withLock {
counter++
}
}
}
- synchronized ๋ธ๋ก๊ณผ์ ์ฐจ์ด์ ์ ์ค๋ ๋๋ฅผ ๋ธ๋กํนํ๋ ๋์ ์ฝ๋ฃจํด์ ์ค๋จ์ํจ๋ค๋ ์ ์ ๋๋ค.
- ์ฑ๋ฅ์ด ์ข์ง๋ง ์ฌ์ฉํ๊ธฐ ์ด๋ ค์ฐ๋ฉฐ, ์๋์ ๊ฐ์ ๋ฌธ์ ์ ์ด ์์ต๋๋ค.
- ์ฝ๋ฃจํด์ด ๋ฝ์ ๋ ๋ฒ ํต๊ณผํ ์ ์์ต๋๋ค.
- ์ฝ๋ฃจํด์ด ์ค๋จ๋์์ ๋ ๋ฎคํ ์ค๋ฅผ ํ ์ ์์ต๋๋ค.
suspend fun main() {
val mutex = Mutex()
mutex.withLock {
mutex.withLock {
// in mutex
}
} // ๋ฝ์ ๋๋ฒ ์ฌ์ฉํ์ฌ ์์ํ ์คํ
coroutineScope {
launch {
delay(10000)
mutex.withLock {
// in mutex
}
}
} // delay๊ฐ ์๋ชจ๋ ๋๊น์ง mutex๋ฅผ ํ ์ ์์
}
์ธ๋งํฌ์ด
- ๋ฎคํ ์ค์ ๋น์ทํ๊ฒ ์๋ํ์ง๋ง, ๋ ์ด์์ด ์ ๊ทผํ ์ ์๋ค๋ ํน์ง์ด ์์ต๋๋ค.
- ์ธ๋งํฌ์ด๋ ์ฌ๋ฌ ๊ฐ์ ์ ๊ทผ์ ํ์ฉํ๋ฉฐ, acquire, release, withPermit ํจ์๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
suspend fun main() = coroutineScope {
val semaphore = Semaphore(2)
launch {
semaphore.withPermit {
}
}
}
- ์ธ๋งํฌ์ด๋ ๊ณต์ ์ํ๋ก ์ธํ ๋ฌธ์ ๋ฅผ ์ง์ ์ ์ผ๋ก ํด๊ฒฐํ ์ ์์ง๋ง, ๋์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ์๋ฅผ ์ ํํ ๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ์ด๋ ์ฒ๋ฆฌ์จ ์ ํ ์ฅ์น๋ฅผ ๊ตฌํํ ๋ ๋์์ด ๋ฉ๋๋ค.
- rate limiter : ํด๋ผ์ด์ธํธ ๋๋ ์๋น์ค๊ฐ ๋ณด๋ด๋ ํธ๋ํฝ์ ์ฒ๋ฆฌ์จ์ ์ ์ดํ๊ธฐ ์ํ ์ฅ์น
class LimitedNetworkUserRepository(
private val api: UserApi
) {
private val semaphore = Semaphore(10)
suspend fun requestUser(userId: String) =
semaphore.withPermit {
api.requstUser(userId)
}
}
์์ฝ
- ๊ณต์ ์ํ๋ฅผ ๋ณ๊ฒฝํ ๋ ์ถฉ๋์ ํผํ๊ธฐ ์ํด ์ฑ๊ธ์ค๋ ๋๋ก ์ ํ๋ ๋์คํจ์ฒ๋ฅผ ์ฌ์ฉํด ๊ณต์ ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ ๋ฐฉ๋ฒ์ ์ฃผ๋ก ํ์ฉํฉ๋๋ค.
- ํ์ธ ๊ทธ๋ ์ธ๋ ์ค๋ ๋ ํ์ : ๋๊ธฐํ๊ฐ ํ์ํ ํน์ ์ฅ์๋ง ๋ํ
- ์ฝ์ค ๊ทธ๋ ์ธ๋ ์ค๋ ๋ ํ์ : ์ ์ฒด ํจ์๋ฅผ ๋ํ
- ์ด ์ธ์ ์์์ฑ, ๋ฎคํ ์ค, ์ธ๋งํฌ์ด๋ฅผ ํ์ฉํ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.