묻고 답해요
156만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨2시간으로 끝내는 코루틴
코루틴 실행 순서 궁금합니다.
안녕하세요.먼저 선생님 강의가 도움 많이 되고 있습니다.감사합니다. 질문이 두 가지 있습니다.질문 1.fun main() = runBlocking { println("START") launch { println("1") } launch { println("2") } launch { println("3") } launch { println("4") } yield() println("END") }이런식으로 되어 있다면yield실행 후에 1~4번 중 어떤게 출력될지는 랜덤인건가요?실제 실행 시에는 순서대로 되는걸 확인 했는데, 이게 항상 launch가 호출된 순서대로 출력되는건가요?질문 2.fun main() = runBlocking { println("START") launch { println("1") } launch { println("2") } launch { yield() println("3") } launch { println("4") } yield() println("END") }만약 3번에 yield 가 있다면, 어떻게 되는건가요?3번에 들어온 순간 끝나지 않은 Coroutine 중에서 랜덤하게 호출되는건가요?아니면 main으로 가서 END가 출력되는건가요?감사합니다.
-
미해결2시간으로 끝내는 코루틴
corutine task에 대한 질문
안녕하세요! 강의 정말 잘보고 있습니다. 한 가지 질문이 있는데요. 스레드도 많이 생성될 경우 컴퓨터의 자원을 빠르게 소모하여 서버가 다운될 수 있기 때문에 스레드 풀로 관리를 할텐데 코루틴의 경우에도 코루틴 자원을 무분별하게 많이 생성을 방지하기 위해 별도의 pool 같은게 있을까요?
-
미해결2시간으로 끝내는 코루틴
completing의 존재의의가 궁금합니다.
안녕하세요? 강의 정말 잘 듣고 있습니다. 세심한 답변도 감사드립니다. 강의를 듣던중 궁금증이 생겼는데요,completing이라는 status의 의의가 좀 궁금합니다. 강의예시로 보여주신 코드는 대략 아래와 같은 느낌이였는데요, 이경우 두번째 자식 코루틴 취소 -> 부모로 전파 -> 다른 자식으로 전파(취소요청) -> 취소 된다는 부분은 이해했습니다.fun main(): Unit = runBlocking { launch { delay(700L) printWithThread("First Child Corutine") } launch { delay(500L) throw IllegalArgumentException("Second Child Corutine Exception~~~!") } } 그런데 강사님이 말씀해주신 completing은 마치 특정 코루틴의 작업이 완료되어도, 다른 코루틴의 작업이 실패했을 때 다시 취소처리하기 위한(그래서 Structured Concurrency를 달성하기 위한) 수단인것처럼 말씀해주셨는데, 실제로 어떤식으로 동작하는지를 잘 이해가 안갑니다 예를 들어 제가 처음 강의를 들었을 때는, 아래의 코드에서 우선적으로 첫번재 launch 실행 -> completing상태 -> 두번째 launch 실행 -> 예외발생 -> 첫번재 코루틴이 다시 cancelling이 되어야 한다고 이해했는데..그러면 아래 코드에서 첫번째 코루틴에서 cancellationException이 잡혀서 "First Child Coroutine caught an exception: ${e.message}" 가 출력되어야 할 것 같은데 그러지 않더라구요. 아마 첫번째 코루틴이 completing이 아닌 completed상태가 되어서 더이상 영향을 받지 않게 되는 것 같은데.. completing이 정확히 어떤 상태인지가 궁금합니다fun main(): Unit = runBlocking { launch { try { delay(500L) println("First Child Coroutine Completed Successfully") } catch (e: Exception) { println("First Child Coroutine caught an exception: ${e.message}") } } launch { delay(700L) throw IllegalArgumentException("Second Child Corutine Exception~~~!") } } // 출력결과 First Child Coroutine Completed Successfully Exception in thread "main" java.lang.IllegalArgumentException: Second Child Corutine Exception~~~! ...
-
미해결2시간으로 끝내는 코루틴
코루틴 dispatcher IO관련 질문
안녕하세요 강사님? 강의 잘 듣고 있습니다. 듣다보니 몇가지 궁금증이 생겨서 질문드립니다. 너무 쉬운 질문들도 있겠지만, 선생님의 답변을 통해 확신을 얻고 싶은 마음이 있어 질문드립니다 __)동기적 호출을 전제하는 동작, 예를 들 FeignClient기반의 호출을 다른 스레드(DISPATCHER.IO)에위임하지 않고 기존 스레드에서만 코루틴형태로 동작시키면, 이때에도 여전히 의도와 다르게 블락킹될 것 같은데 맞을까요? 강의에서 보여주신 예시중에 아래와같은 예시가 있는데, 이 경우에는 하나의 스레드만 사용하시는 것 같아 혹시나 하는 마음에 여쭤봅니다. // Async 사용 fun main(): Unit = runBlocking { val time = measureTimeMillis { val job1 = async { apiCall1() } val job2 = async { apiCall2() } printWithThread(job1.await() + job2.await()) } printWithThread("소요시간 : $time") } // 출력 결과 [main] 소요시간 : 1030 IO를 효율적으로 진행하기 위해서는 결국 Dispatcher I.O의 스레드들에게 위임해야 할 것 같은데그렇다면 애초부터 Dispatcher I.O의 스레드들은 ‘블락킹당해도 괜찮다’를 전제로 만들어진 스레드들(스레드풀)인걸까요?그러면 결론적으로 Dispatcher IO는 블락킹 당해도 괜찮을 수 있도록 어떤식으로 처리되어 있는 건지 궁금합니다.
-
미해결2시간으로 끝내는 코루틴
Job 질문이 있습니다
이전 강의 설명에서 아래의 코드가 실행될 때 launch로 만든 코루틴이 바로 실행되지 않고 다음 코드로 넘어간다고 했는데fun main(): Unit = runBlocking { println("START") launch { newRoutine() } println("END") }왜 아래의 코드에서는 job 객체를 변수에 담으면 다음 코드로 넘어가는게 아니라 바로 실행이 되는건가요?fun main(): Unit = runBlocking { val job = launch { (1..5).forEach { printWithThread(it) delay(500) } } delay(1_000L) job.cancel() }
-
해결됨2시간으로 끝내는 코루틴
스프링 MVC 환경에서의 코루틴
안녕하세요.Spring MVC 환경에서 코루틴을 사용할 때 질문이 있습니다. (WebFlux 사용 X)다음과 같은 코드가 있다고 가정하겠습니다. 컨트롤러@GetMapping("/test") suspend fun test(): ApiResponse<Void> { testService.run() return ApiResponse.success(statusCode = HttpStatus.OK) }서비스class TestService( private val userRepository: UserRepository, ) { suspend fun run(): Triple<String, String, Int> { // 외부 API 호출 1 val nicknameDeferred = CoroutineScope(Dispatchers.IO).async { callApiForNickname() } // 외부 API 호출 2 val addressDeferred = CoroutineScope(Dispatchers.IO).async { callApiForAddress() } // Do something business logic // DB 호출 val duplicateCount = userRepository.findDuplicateCountById(1L) return Triple(first = nicknameDeferred.await(), second = addressDeferred.await(), third = duplicateCount) } }(callApiFor~() 메소드는 외부 API 호출이라고 가정하며 suspend function입니다)서비스 레이어에서는 2개의 외부 API 호출을 수행하고 DB호출을 한 후 리턴해주는 간단한 구조입니다. 질문초기에는 내부적으로 코루틴을 사용할 지 말지 결정할 수 없는 상황이 있기에 모든 컨트롤러 메소드를 suspend로 선언하는건 어떨까 합니다. (2번 질문의 성능 차이가 크지 않다면요^^) 이 부분에 대해 강사님의 생각과 실무에서는 보통 어떻게 하는지 궁금합니다.위 질문에 이어서, 코루틴이 전혀 사용되지 않는 상황에서 컨트롤러 메소드를 suspend로 선언하면 일반 메소드로 선언하는것과 성능차이가 어느정도 있을까요? (물론 트래픽 등 기타 상황별로 다르겠지만요)서비스 레이어를 보면 CoroutineScope을 통해 각 외부 API호출별로 루트 코루틴을 따로 만들고 있습니다. 각 외부 API들은 단순 조회 요청으로써 구조적 동시성이 필요하지 않다고 생각하기 때문인데요. 실무에서도 위와 같이 여러개의 외부 API호출을 병렬로 수행해야하는 경우 각 호출마다 CoroutineScope을 사용하여 개별로 루트 코루틴을 만들어서 사용하는지 궁금합니다.일반적인 웹 API 서버 개발을 수행할 때 구조적 동시성이 필요한 케이스가 있을까요? 어차피 추후 로직을 통해 반환값에 대한 검증을 수행한다고 생각해서요. 예를 들어 A, B, C를 코루틴으로 호출할 때 A가 실패해서 B, C를 취소하려해도 각 메소드의 레이턴시에 따라 취소될수도, 이미 완료됐을수도 있을 것 같습니다. 실무에서 웹 API 비즈니스 로직 구성 시, 개별 루트 코루틴이 아닌 하나의 루트 코루틴으로 묶어서 구조적 동시성을 보장해야만 하는 상황이 있을지, 있다면 무엇일지 궁금합니다.감사합니다.
-
미해결2시간으로 끝내는 코루틴
자식1, 2와 부모코루틴의 관계
본 강의를 모두 수강하였습니다! 코루틴에서 헷갈렸던 개념들을 알 수 있어서 좋았습니다!본 코루틴 강의에서 자식과 부모 관계의 에러가 발생했을 때 에러 핸들링 하는 경우는 자식이 하나만 존재했을 때의 예시밖에 없어서 직접 2개를 가지고 실험을 해보았습니다! 먼저, 자식1이 취소가 됐을 때에는 취소예외가 발생했기 때문에 부모로 전파되지 않고, 그러므로 다른 자식2도 영향을 받지 않는다 라고 이해를 하고 있습니다!하지만 자식1에서 취소가 아닌 예외가 발생했을 경우 부모로 전파되는 것으로 알고있고, 이 때 적절한 조치가 되지 않는다면 자식2까지 취소되는 것으로 알고있습니다!따라서 다음과 같이 CoroutineExceptionHandler를 적용해보았습니다.fun main() = runBlocking { val handler = CoroutineExceptionHandler { _, exception -> println("Caught exception: $exception") } val parentJob = CoroutineScope(Dispatchers.Default).launch(handler) { val job1 = launch { println("Job 1 is running") throw RuntimeException("Error in Job 1") } val job2 = launch { println("Job 2 is running") delay(1000) println("Job 2 is completed") } job1.join() job2.join() } parentJob.join() println("Parent job is completed") }Job 1 is runningCaught exception: java.lang.RuntimeException: Error in Job 1Parent job is completed결과는 자식1만 실행이되고, 거기서 Exception을 던졌는데, Job2는 취소되는것으로 보입니다..!질문 1 ) 다음과 같이 try catch 로 전환하면 자식2의 취소가 발생하지 않는데, CoroutineExceptionHandler로는 자식2의 취소를 막을수는 없는 것일까요?val job1 = launch { println("Job 1 is running") try { throw RuntimeException("Error in Job 1") } catch (e: RuntimeException) { println("RuntimeException") } }질문 2) 강의내용에서는 SupervisorJob() 을 사용하면 부모 코루틴으로 예외가 전파되지 않는다고 해주셨는데, 다음 결과에서는 부모코루틴에 해당되는 CoroutineExceptionHandler 가 실행되는 것으로 보입니다. 하지만, 질문1에서 걱정하는 자식2의 취소로 이어지지 않고 있습니다. 이는 부모코루틴으로 예외가 전파되는 상황일까요?? 만일 전파되는 상황이라면 왜 질문1과는 다르게 자식2의 취소로 이어지지 않는 것일까요?fun main() = runBlocking { val handler = CoroutineExceptionHandler { _, exception -> println("Caught exception: $exception") } val parentJob = CoroutineScope(Dispatchers.Default).launch(handler) { val job1 = launch(SupervisorJob()) { println("Job 1 is running") throw RuntimeException("Error in Job 1") } val job2 = launch { println("Job 2 is running") delay(1000) println("Job 2 is completed") } job1.join() job2.join() } parentJob.join() println("Parent job is completed") }Job 1 is runningJob 2 is runningCaught exception: java.lang.RuntimeException: Error in Job 1Job 2 is completedParent job is completed자바 -> 코틀린 강의부터 시작해서 코루틴 강의까지 너무 감사하게 잘 보고있습니다! 감사드립니다 🙂
-
해결됨2시간으로 끝내는 코루틴
한 suspend fun 의 반환값이 다른 suspend fun의 파라미터로 쓰일 때
fun main(): Unit = runBlocking { val job1 = async { apiCall1() } val job2 = async { apiCall2(job1.await()) } printWithThread(job2.await()) } suspend fun apiCall1(): Int { delay(1_000L) return 1 } suspend fun apiCall2(num: Int): Int { delay(1_000L) return num + 2 }위와 같은 코드에서, 코루틴을 사용해도 apiCall1() 의 반환값이 apiCall2()의 인자로 사용되기 때문에, apiCall1()이 완료된 후에 apiCall2()가 실행되는 것은 이해했습니다. 그리고 코루틴을 사용할 때의 이점이 마치 한줄한줄 동기식 코드를 작성할 때처럼 비동기 코드를 사용할 수 있다. 로 이해했습니다.그럼 위와 같은 상황에서는 굳이 코루틴을 사용하지 않고, 아래와 같이 동기적으로 코드를 작성해도 같은 것일까요? (두 apiCall1,2를 사용하는 외부 메서드가 없을 때)fun main() { val job1 = apiCall1() val job2 = apiCall2(job1) printWithThread(job2) } fun apiCall1(): Int { delay(1_000L) return 1 } fun apiCall2(num: Int): Int { delay(1_000L) return num + 2 }비동기 처리가 처음이다 보니 직관적으로 잘 와닿지 않는 부분이 많아 자꾸 질문드리네요 ㅜㅜ 죄송합니다.
-
해결됨2시간으로 끝내는 코루틴
delay 함수에 대해 질문이 있습니다
강의 듣던 와중 delay에 대한 궁금증이 생겨서 질문드립니다.만약 한 코루틴에서 delay로 시간을 전부 보낸 후에는 작업 중인 다른 코루틴에게서 제어권을 뺏어오게 되나요?아래와 같은 예시에서fun main(): Unit = runBlocking { val job1 = launch { delay(100) printWithThread("Job 1") } val job2 = launch { // 대충 0.1초보다 더 걸리는 로직 } }위와 같은 상황에서는job1에서 delay로 0.1초 기다림과 동시에 job2에게 넘겨줌job2 실행중job1에서 기다리기로 약속한 0.1초 지남하지만 job2 아직 실행중이 상황에서는 job2의 로직이 전부 끝난 후에 job1에게 제어권을 넘겨주게 되는 걸까요?
-
해결됨2시간으로 끝내는 코루틴
runBlocking을 사용하는 경우가 있을까요?
안녕하세요, 좋은 강의 잘 듣고 있습니다.runBlocking 설명하시면서, runBlocking은 자신의 코루틴이 모두 실행될 때까지 Thread를 Blocking 시킨다. 그래서 main 함수 최초 진입점이나, 테스트 코드 맨처음에 작성하는 것이 좋다. 라고 말씀해 주셨습니다.그런데 그럼 테스트 코드 전체 또는 main 함수 전체를 코루틴으로 작성할 경우에만 사용이 되는 걸까요? 테스트 코드 이외에는 실제 로직에서 어떤 경우에 사용이 될지 궁금합니다.아직 강의 초반부라서 이해가 부족한 것인가 싶기도 하지만 실시간으로 궁금해서 여쭤봅니다.
-
미해결2시간으로 끝내는 코루틴
delay가 없으면 실행 안 되는 이유
안녕하세요! 좋은 강의 잘 듣고 있습니다.😄5강 수강 중인데, 여기에서 fun lec05Example2(): Unit = runBlocking { val job = CoroutineScope(Dispatchers.Default).launch { throw IllegalArgumentException() } delay(1_000L) }delay(1_000L) 부분이 없으면 위의 예외 던지는 코루틴을 실행을 안 하던데 왜 그런지 이유를 잘 모르겠습니다.
-
미해결2시간으로 끝내는 코루틴
코루틴 스코프
코드를 보다보면 코루틴 스코프를 쓸 때, 소문자로 coroutineScope { } 블락이 있는 경우가 있고 대문자로 시작하는 CoroutineScope(Dispatchers.Main).launch { } 이런식으로 된 코루틴스코프가 있는데, 각각 어떤 차이이며 어느 상황에 각각을 써야하나요?
-
미해결2시간으로 끝내는 코루틴
CoroutineScope 와 withContext 의 차이를 잘 모르겠습니다.
강의를 듣다보면 CoroutineScope 와 withContext 의 차이를 정확히 모르겠습니다. withContext 는 context 에 변화를 줄 수 있어서 withContext(Dispatchers.Default) 이런 식으로 쓴다고 하는데, CoroutineScope 도 동일하게 CoroutineScope(Dispatchers.Default).launch 이런식으로 context 를 설정해줄 수 있는데 어떨 때 CoroutineScope 를 쓰고 어떨 때 withContext 를 쓰는지 잘 모르겠습니다.
-
해결됨2시간으로 끝내는 코루틴
Dispatchers 관련 궁금증입니다.
withContext(Dispatchers.IO) { println(“AA : ${Thread.currentThread().name}") val asyncOrigin = async { println(“BB : ${Thread.currentThread().name}") origin.invoke() }} // 결과AA : DefaultDispatcher-worker-1 @coroutine#2BB : DefaultDispatcher-worker-3 @coroutine#3 안녕하세요.Dispatchers 사용부분이 궁급함니다. 따로 asyncOrigin에서 Dispatchers를 다르게 쓰겠다고 설정한게 없는데 결과가 의문이였습니다. 물론 코루틴은 각자 실행이여서 코루틴의 번호가 다른건 이해했습니다만,부모꺼의 스레드를 가져다 쓸거다라고 생각했는데 스레드도 부모꺼를 안쓰고 다른게 맞는걸까요?어떤 원리인지 궁금합니다.
-
해결됨2시간으로 끝내는 코루틴
yield 함수가 없어도 결과가 동일한 이유가 뭔가요?
yield 함수를 지워도 실행을 했을 때 출력 순서가 동일한 이유가 궁금합니다!runBlocking 으로 실행한 코루틴과 launch 로 실행한 코루틴의 순서가 변경됐던 이유가 yield 때문이 아니기 때문일까요?
-
해결됨2시간으로 끝내는 코루틴
코루틴 Job 상속에 관하여 질문드려요
안녕하세요 강사님~ 좋은 강의 너무 감사드립니다. 덕분에 코루틴 입문을 쉽게 할 수 있었습니다.다름이 아니라 강사님 강의를 완강하고나서 코루틴 관련 책을 보고 있는데요,Job은 자식에게 상속되지 않는 유일한 코루틴 컨텍스트라는 내용이 있네요.이곳저곳 더 찾아보니 부모 코루틴을 기반으로 고유한 Job을 갖는다는 내용이 있는데 정확히 이게 어떤 의미인지 모르겠어서 질문을 드립니다!
-
미해결2시간으로 끝내는 코루틴
코루틴 취소 관련 질문
fun main(): Unit = runBlocking { val job = launch { var i = 1 var nextPrintTime = System.currentTimeMillis() while (i <= 5) { if(nextPrintTime <= System.currentTimeMillis()){ printWithThread("${i++}번째 출력!") nextPrintTime += 1_000L } } } delay(100L) job.cancel() }수업 때 예시로 보여주신 코드인데 이 코드는 "5번째 출력!"까지 출력하고 끝이 나는데요. 반면에 아래 코드는 한번만 출력하고 끝이 납니다.fun main(): Unit = runBlocking { val job = launch { var nextPrintTime = System.currentTimeMillis() repeat(5) { if (nextPrintTime <= System.currentTimeMillis()) { printWithThread("${it + 1}번째 출력!!") nextPrintTime += 1_000L } } } delay(100L) job.cancel() }이는 단순히 repeat문이 무한루프가 아니어서 나오는 차이일까요?
-
미해결2시간으로 끝내는 코루틴
single thread에서 여러개의 co-routine ( 각각 서버연동을 수행 ) 을 순차적이 아닌 concurreny 하게 수행하게 할방법은 없나요?
single thread에서 여러개의 co-routine ( 각각 서버연동을 수행 ) 을 순차적이 아닌 concurreny 하게 수행하게 할방법은 없나요? 상황Single Thread ㄴ co-routine (1) : 서버연동 ( 사용자 정보를 요청 )ㄴ co-routine (2) : 서버연동 ( 회원등급 정보 요청) 테스트 결과co-routine (1)이 실행완료 -> co-routine(2) 수행 동시적으로 서버에 요청하지 않음 CoroutineScope(Dispatchers.Default)로 설정하여 각각 쓰레드를 생성하면 동시적으로 수행되나,이럴경우 co-routine을 사용해야 되는 의미가 필요한지 의문이 생김결국 multi thread가 발생했다는건 context swiching이 발생한다는 뜻인데. 오히려 이럴 바에는 co-routine을 사용하지 않고 multi thread만 사용해서 해당 코드를 수행하는것고 어떤 차이가 있는지잘 모르겠습니다.제 의문에 대한 명쾌한 대답을 듣고 싶습니다.
-
미해결2시간으로 끝내는 코루틴
suspend function의 일시 중단 여부는 어떻게 결정되나요?
안녕하세요 강사님, 좋은 강의에 항상 감사드리고 있습니다! 다른게 아니라, 강의 중 suspend function은 일시 중단 되었다가 재개될 수도 있고 / 그렇지 않을 수도 있다고 설명 주셨습니다. 그렇다면 실제로 suspend function이 일시 중단되어야 하는지 여부는 어떻게 결정되나요?단순히 suspend function 내부에서 또 다른 suspend function을 호출하기만 하면 무조건 일시 중단 되는 것인지, 아니면 Node.js 진영의 libuv 라이브러리처럼 비동기적으로 처리되어야 하는 IO 작업을 내부적으로 인지하는 방식이 별도로 구현되어 있는지 궁금합니다!
-
미해결2시간으로 끝내는 코루틴
코루틴이 자바 reactive streams 대신에 쓸 수 있는 것일까요?
추후에 자바 프로젝트를 코틀린으로 컨버팅할 계획을 가지고 있는데 자바의 비동기 라이브러리인 reactive streams를 코루틴이 대체할 수 있을까 해서요