Do it! 코틀린 프로그래밍 [셋째마당, 코틀린 표준 라이브러리의 활용] 학습
fun main() = runBlocking<Unit> {
val jobs = arrayListOf<Job>()
// (4) Unconfined 문맥
jobs += launch(Dispatchers.Unconfined) {
println(Thread.currentThread().name)
}
jobs += launch(coroutineContext) {
println(Thread.currentThread().name)
}
// (1) 디스패처의 기본값
jobs += launch(Dispatchers.Default) {
println(Thread.currentThread().name)
}
// (2) 입출력 중심의 문맥
jobs += launch(Dispatchers.IO) {
println(Thread.currentThread().name)
}
jobs += launch {
println(Thread.currentThread().name)
}
// (3) 새 스레드를 생성
jobs += launch(newSingleThreadContext("MyThread")) {
println(Thread.currentThread().name)
}
jobs.forEach { it.join() }
}
GlobalScope.launch{}와 같은 표현📌 repeat() 함수를 사용한 반복 동작하기
repeat()함수 이용GlobalScope.launch {
repeat(1000) { i ->
delay(500L)
}
}
-> repeat()함수에 인자를 주어 1000회 반복
-> GlobalScpoe로 생명주기를 한정했기 때문에 메인 스레드가 종료되면 더 이상 진행되지 않음
-> 만약 GlobalScope를 제거하면 모든 횟수를 진행할 때까지 프로그램이 종료되지 않음
📌 코루틴 작업 취소하기
join()함수만 사용하면, main()함수가 job의 완료를 기다리게됨cancel()함수를 사용하면 job은 작업을 취소하고 main()을 종료시킴val job = launch {
repeat(1000) {
}
}
delay(1300L)
job.cancel()
-> job을 1000번 반복하기 전에 1.3초 후 main()함수는 종료됨
📌 finally의 실행 보장
...
} finally {
withContext(NonCancellable) { // finally의 완전한 실행을 보장
delay(1000L)
println("Non-Cancellable") // 1초를 지연해도 취소되지 않음
}
}
📌 코루틴의 시간 만료
withTimeout() 함수 사용fun main() = runBlocking<Unit> {
try {
withTimeout(1300L) { // Timeout 예외 발생
repeat(1000) {
delay(500L)
}
}
} catch (e: TimeoutCancellationException){
}
}
-> 예외가 아닌 null로 처리하려면 withTimeoutOrNull()을 사용
fun main() = runBlocking<Unit> {
val channel - Channel<Int>()
launch {
for (x in 1..5) channel.send(x * y)
}
repeat(5) { println(channel.receive) }
}
-> 채널을 통해 send() 함수로 값을 보내 놓으면 이후 receive() 함수를 통해 값을 받을 수 있음
-> 일반 큐와는 다르게 더이상 전달 요소가 없으면 채널을 닫을 수 있음
-> for문을 구성해 채널을 받고 close()를 사용하면 바로 채널을 닫는 것이 아니라 닫겠다는 특수한 토큰을 보냄
// 생산자를 위한 함수 생성
fun CoroutineScope.producer(): ReceiveChannel<Int> = produce {
val total: Int = 0
for (x in 1..5) {
total += x
send(total)
}
}
fun main() = runBlocking {
val result = producer() // 값의 생산
result.consumeEach { print($it) } // 소비자 루틴 구성
}
📌 버퍼를 가진 채널
send() 함수가 먼저 호출되면 receive() 함수가 호출되기 전까지 send() 함수는 일시 지연Channel() 생성자의 capacity 매개변수를 통해 버퍼 크기를 정할 수 있음fun main() = runBlocking {
val channel = Channel<Int>(2) // 버퍼 capacity 값을 줌
val sender = launch(coroutineContext) { // 송신자 측
repeat(10) {
channel.send(it) // 지속적으로 보내다가 꽉 차면 일시 지연
}
}
delay(1000) // 아무것도 받지 않고 1초 기다린 후
sender.cancel() // 송신자의 작업을 취소
}