본문 바로가기
코틀린 문법

23. 코루틴을 통한 비동기 처리

by 농농씨 2023. 6. 4.

참조: 유튜브 디모의 코틀린

코드테스트사이트:play.kotlinlang.org

단축키(맥북):

맥북 스크린샷 바로 클립보드에 붙여넣기

-control+command+shift+3 or 4(3은 전체화면, 4는 마우스로 지정한 영역, 4일때 스페이스바 누르면 창캡처가능)

화면에 분할해놓은 창끼리 이동

-command+'

한 창에서 탭끼리 이동

-command+shift+{/}

 

//비동기로 여러개의 루틴을 동시에 처리할 수 있는 방법
//여태까지 하나의 구문이 끝나면 다른 구문을 실행하는 식으로
//모든 구문을 '동기적'으로 실행함
//하지만 '여러개의 루틴'을 동시에 실행하여 결과를 내고 싶다면?
//-->비동기처리를 지원하는 '코루틴(coroutine)' 사용
//코루틴이란?
//메인이 되는 메인루틴과 별도로 진행이 가능한 루틴으로,
// 개발자가 루틴의 실행과 종료를 마음대로 제어할 수 있는 단위
//코루틴을 사용할 때는 코틀린extention에 코루틴s패키지를 모두 import해야함
//import kotlinx.coroutines.*
//
//코루틴의 Scope
//코루틴은 제어범위 및 실행범위 지정 가능
//기본적으로 GlobalScope, CoroutineScope 지원함
//<GlobalScope
// 프로그램 어디서나 제어,동작이 가능한 기본범위
//<CoroutineScope
// 특정한 목적의 Dispatcher를 지정하여 제어 및 동작이 가능한 새로운 코루틴범위
//<Coroutine의 dispatcher?
// CoroutineScope를 만들 때 적용가능한 Dispatcher
// Dispatchers.Default : 기본적인 백그라운드 동작
// Dispatchers.IO : I/O에 최적화된 동작
// Dispatchers.Main : 메인(UI) 스레드에서 동작
// 이러한 Dispatcher들은 모든 플랫폼에서 지원되지는 않으니 지원되는플랫폼따라 사용
//코루틴은 이러한 scope에서 제어되도록 생성될 수 있음
//생성된 스코프에서 launch나 async(어싱크)라는 함수를 통해 새로운 코루틴을 생성할 수 있음
//ex. val scope=CoroutineScope(Dispatcher.Defaunt)(생성된스코프)
//   val coroutineA=scope.launch{}
//   val coroutineB=scope.async{}
//launch vs async :코루틴에서의 반환값이 있는지의 여부 차이!
//launch : 반환값이 없는 Job 객체를 반환
//ex. launch{
// for(i in 1..10){
//   println(i)
// }
//   }
//async : 반환값이 있는 Deffered 객체 
//ex. async{
//     var sum = 0
//     for(i in 1..10){
//       sum++
//     }
//     sum -->이 값이 반환됨!
//   }
//둘다 람다함수의 형태를 가지고 있으며
// 그렇기 때문에 async는 마지막 구문의 실행결과가 반환됨

import kotlinx.coroutines.*
//를 선언하여 코루틴 관련 라이브러리를 import함


fun main(){
    
    val scope=GlobalScope
    //globalscope를 변수 scope에 받은 뒤 
    
    //이 scope에서 launch로 Job객체의 코루틴을 하나 만듦
    scope.launch{
        for(i in 1..5)//내용은 for문 통해 1부터 5까지 반복하며 숫자출력
        {
            println(i)
        }
    }
    
}
//실행해보면 아무런 결과 안나옴(어... 나오는데... 기다려주네 친절하게)
//당연함
//코루틴은 제어되는 스코프 또는 프로그램 전체가 종료되면 함께 종료되기 때문 
//코루틴이 끝까지 실행되는 것을 보장하려면 일정한 범위에서 코루틴이 모두
//실행될때까지 잠시 기다려주어야 함
//우리가 테스트하는 루틴의 경우 main()함수 단 하나이기 때문에 
//프로세스가 거의 '실행 즉시 종료'되므로 코루틴도 동작되지 못했음 
//이럴때는 runBlocking block을 만들고 이 안에서 launch{}나
//async{}를 직접 생성하면 코루틴이 종료될때까지 메인루틴을 잠시 대기시켜줌
//ex. runBlocking {
//     launch{}
//     async{}
//   }
//*주의할점
//안드로이드에서는 메인스레드에서 runBlocking을 걸어주면 일정 시간 이상
//응답이 없는 경우 ANR(Application Not Responding:응답 없음 오류)이
//발생하며 앱이 강제 종료됨을 유의


import kotlinx.coroutines.*

fun main(){
    
    runBlocking {
        //runBlocking 블럭을 생성하고 launch 직접 생성하여 
        //아까처럼 1부터 5까지 반복하며 숫자출력
        launch{
            for(i in 1..5)
            {
                println(i)
            }
        }
        
    }
    
}



//루틴의 대기를 위한 추가적인 함수들
//delay(),join(),await()
//<delay(milisecond:Long)
//milisecond 단위로 루틴을 잠시 대기시키는 함수
//<Job.join()
//Job 객체에서 호출하여 Job의 실행이 끝날때까지 대기하는 함수
//<Deferred.await()
//Deffered 객체에서 호출하여 Deferred의 실행이 끝날때까지 대기하는 함수
//+await()는 Deferred의 결과도 반환함 
//세 함수들은 코루틴 내부 또는 runBlocking{}과 같은 
//루틴의 대기가 가능한 구문 안에서만 동작이 가능함


import kotlinx.coroutines.*

fun main(){
    
    runBlocking {
        val a=launch{//launch로 실행된 Job객체를 변수a에 받음 
            for(i in 1..5)
            {
                println(i)
                delay(10)
                //launch함수의 동작을 일부러 늦추기 위해
                //for문 안에 delay를 10정도 넣음 
            }
        }
        val b=async{
            //async로 새로운 deferred객체 생성하여 변수b에 받음 
            "async 종료"//간단하게 async종료 라는 문자열을 반환
        }
        
        println("async 대기")//메인루틴에서 async대기라는 문자열 출력
        println(b.await())//b에 await()를 걸어준 결과를 출력
        
        println("launch 대기")//다시 문자열 출력
        a.join() //a에 join 걸어 대기
        println("launch 종료")
    }
    
}
//실행해보면, await() 함수에서 결과를 받아 출력하고 
//다시 launch가 끝까지 수행되기를 기다린 후 
//launch가 종료되었음을 출력



//코루틴 실행 도중에 중단하는 방법
//cancel()
//코루틴에 cancel()을 걸어주면
//다음 두가지 조건이 발생하며 코루틴을 중단시킬 수 있음
//1.코루틴 내부의 delay() 함수 또는 yield()함수가 사용된 위치까지 
// 수행된 뒤 종료됨
//2.cancel()로 인해 속성인 isActive가 false가 되므로
// 이를 확인하여 수동으로 종료함


import kotlinx.coroutines.*

fun main(){
    
    runBlocking {
        val a=launch{
            for(i in 1..5)
            {
                println(i)
                delay(10)
            }
        }
        val b=async{
            "async 종료"
        }
        
        println("async 대기")
        println(b.await())
        
        println("launch 대기")
        a.cancel()//a.join()대신 a.cancel()을 수행
        println("launch 취소")//launch 대기 대신 취소 출력
    }
    
}
//실행해보면 아까와는 달리 코루틴의 작업이 중간에 취소되어 
//숫자가 끊김

//withTimeoutOrNull() 함수
//제한시간 내에 수행되면 결과값을, 아닌 경우 null을 반환함
//괄호 안에 밀리세컨드 단위의 timeout시간을 정해두고
//중괄호 안에 코루틴 구문들을 만든 후
//그 결과값을 받는 형태
//join()이나 await()처럼 blocking함수라는 점 기억!
//ex. withTimeoutOrNull (50){
//     for(i in 1..1000){
//       println(i)
//       delay(10)
//     }
//     "Finish"
//   }


import kotlinx.coroutines.*

fun main(){
    
    runBlocking{//runBlocking 블럭 만들고
        var result = withTimeoutOrNull(50){
            //withTimeoutOrNull에 timeout값으로 50ms주고  
            for(i in 1..10){
                //for문 이용해 1부터 10까지 출력
                println(i)
                delay(10)
                //실행속도 일부러 늦추기 위해 delay 10 넣음
            }
            "Finish"//끝났다는 의미의 문자열 반환
            //결과값은 result로 받음
        }
        
        println(result)//result값 출력
    }
    
}

//실행해보면 timeout내에 실행할 수 없어 null이 출력됨
//timeout이나 수행되는 내용을 변경해보면서 끝까지 수행되는 경우도 확인해보세요



'코틀린 문법' 카테고리의 다른 글

22. 비트연산  (0) 2023.06.04
21. 변수의 다양한 사용방법  (0) 2023.06.03
20. 컬렉션함수(2)  (0) 2023.06.03
19. 컬렉션함수(1)  (0) 2023.06.03
18. Set과 Map  (0) 2023.05.31