용어 정리
- blocking
var data = getData() // 1
println(data)// 2
- 데이터를 반환하는 함수의 리턴값을 변수에 할당.
- 데이터를 사용할 수 있게 되면 데이터가 출력됨.
데이터를 완전히 얻을 때 까지 프로그램이 멈추게 된다 (1~2 사이) 이를 블로킹작업이라고 한다.
- 병렬성 : 코딩을 하면서 음악을 듣기 (’손’과 ‘귀’을 동시에 사용) - 멀티코어 프로세서의 멀티스레드
- 동시성 : 코딩을 하면서 과자를 먹기 (손을 ‘키보드’와 ‘과자’에 사용) - 코루틴
1. Coroutine이란?
- 애플리케이션을 개발하는 동안 네트워크, 데이터베이스호출 또는 복잡한 계산, api호출, 데이터 다운로드 등등..과 같이 긴 시간에 걸쳐 작업을 수행해야하는 상황이 자주 발생할때 사용한다.
- 백그라운드에서 또는 비동기적으로 위와같은 작업이 시행되게 할 수 있음. → 사용자를 기다리게 하지 않고 웹(앱)을 사용할 수 있게해준다
cf.) Java의 Thread, C#의 async/await
2. Coroutine builders
- Scope
CoroutineScope GlobalScope
| runBlocking | 최상위함수 | 최상위함수 |
| launch | 확장함수 | 확장함수(권장x) |
| async | 확장함수 | 확장함수(권장x) |
- CoroutineScope : 다른 상태를 공유하기 위해 사용한다.
- CoroutineStart - DEFAULT, LAZY, ATOMIC, UNDISPATCHED
- runBlocking
- 명령줄 검증, 테스트
- 현재 스레드를 block하고 모든 내부 코루틴이 종료될때 까지 블록한다.
- 사용하지 않는 것이 좋다고 함
- 예시
- fun <T> runBlocking(block: suspend CoroutineScope.() -> T): T
- launch
- 독립된 프로세스 실행, 해당 코루틴에서 리턴값을 받을 필요가 없을 때 유용
- CoroutineScope의 확장함수이기때문에 CoroutineScope이 사용 가능한 경우에만 사용가능
- 코루틴 취소가 필요할 때 사용할 수 있는 Job인스턴스를 리턴한다.
- 예시
- fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job
- async빌더
- 리턴값이 필요할 때 유용 → await() 을 붙힌 값이 리턴값이다.
- 예시
- fun <T> CoroutineScope.async( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T ): Deferred<T>
- 리턴값인 Deferred<T>는 생산된 값을 리턴하기 전에 코루틴이 완료될때 까지 기다리는 await함수이다.
Job 인스턴스
3. Suspend Function
실행을 잠시 중단하고 자신의 작업을 끝내면 중단했던 작업을 계속 할 수 있는 함수
suspend fun thisIsSuspend(arg: String) : Boolean{
//~~
}
코루틴은 적어도 한 개 이상의 suspend 함수를 필요로 한다.
4. Dispatcher
- 코루틴이 실행될 스레드를 결정하는데, 여기에는 시작될 곳과 중단후 다시 시작될 곳을 모두 포함한다.
- Default :
- Main
- Unconfined : 첫번째 중단지점에 도달할 때까지 현재 스레드에 있는 코루틴을 실행한다. 코루틴은 일시중지된 후에, 일시중단연산에서 사용된 기존 스레드에서 다시 시작된다.
- IO
- newSingleThreadContext() : 일시 중지후에도 항상 같은 스레드에서 실행된다.
- ndwFixedThreadPoo;Context() : 스레드풀에서 알아서 부하분산을 위한 방법을 정함
- 예외처리
- val handler = CoroutineExceptionHandler({context, throwable -> println("$context") println("$throwable.message") }) GlobalScope.launch(handler){ //~~ }
5. 연습
- 아래와 같은 함수를 코루틴을 이용해서 요청시간을 단축시켜보려고 한다.
private fun first(): Long {
println("1st function started")
Thread.sleep(1000L)
println("1st function ended")
return 1L
}
private fun second(num: Long): String {
println("2nd function started")
Thread.sleep(2000L)
println("2nd function ended")
if (num != 1L) {
return "no"
}
return "2"
}
private fun third(str: String): Boolean {
println("3rd function started")
Thread.sleep(1500L)
println("3rd function ended")
return str === "2"
}
fun main() {
val startTime = System.currentTimeMillis()
val firstVal = first()
val secondVal = second(firstVal)
println(third(secondVal))
println(System.currentTimeMillis() - startTime)
}
- 코루틴 → async
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.IO
private suspend fun first() : Long{
println("1st function started $")
delay(1000L)
println("1st function ended")
return 1L
}
private suspend fun second(long: Deferred<Long>) : String{
println("2nd function started")
delay(2000L)
println("2nd function ended")
if(long.await()===1L){
return "success!"
}
return "nope"
}
private suspend fun third(str: Deferred<String>) {
println("3rd function started")
delay(1500L)
println("3rd function ended")
println("done! ${str.await()}")
}
fun main() = runBlocking {
val startTime = System.currentTimeMillis()
val firstVal = async(IO) {
first()
}
val secondVal1 = async(IO) {
second(firstVal)
}
third(secondVal1)
println(System.currentTimeMillis() - startTime)
}
원자적 데이터 구조
- 원자성 : 어떠한 작업이 실행될때 언제나 완전하게 진행되어 종료되거나, 그럴 수 없는 경우 실행을 하지 않는 경우
val counter = AtomicInteger()
fun asyncIncrement(by: Int) = async {
for(i in 0 until by) {
counter.incrementAndGet()
}
참고자료 :코틀린 쿡북, 코틀린 동시성 프로그래밍
'개발' 카테고리의 다른 글
| [Spring] spring security (0) | 2026.10.04 |
|---|---|
| [JPA] hibernate (0) | 2026.10.04 |
| [Springboot] htmlConverter사용해서 pdf파일 만들기(+한글폰트설정) (0) | 2021.07.29 |
| [etc] Error Domain=NSPOSIXErrorDomain Code=86 (0) | 2021.06.21 |
| [SQL] QueryDSL (0) | 2021.06.16 |