묻고 답해요
147만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨코틀린 코루틴 완전 정복
[코틀린 코루틴의 정석 책 추첨 이벤트] 강의 구매 기간 관련 문의
안녕하세요 강사님! 책 추첨 이벤트 관련 내용을 보고 강의 구매 기간에 관련하여 여쭤보고 싶은 사항이 있어서 글을 남기게 됐습니다. 여기에 말씀해주신 기간(25.12.19 ~ 26.1.18)에 강의를 구매한 사람만 해당 이벤트에 참여할 수 있는 걸까요 ?? (기간 이전에 강의를 구매한 사람은 해당되지 않는 지 궁금합니다) 감사합니다.
-
해결됨코틀린 코루틴 완전 정복
[코루틴 테스트 심화] runTest의 스레드 관련 문의
안녕하세요 강사님!강의 복습 중에 runTest 관련 문의가 있어서 다음과 같이 질문을 남기게 됐습니다. 코루틴 테스트 심화강의의 4:07초에 시작되는 부분을 보면 runTest를 호출해 실행되는 코루틴은 메인 스레드를 사용한다라고 해주셨습니다. 제가 실제로 runTest를 이용해 코드를 실행시켜 보니 Test worker스레드를 사용하고 있다고 나왔습니다. 실행 코드 @Test fun `메인 스레드만 사용하는 runTest`() = runTest { println("[${Thread.currentThread().name}] 메인 시작") delay(100) println("[${Thread.currentThread().name}] 메인 종료") }결과[Test worker @kotlinx.coroutines.test runner#2] 메인 시작 [Test worker @kotlinx.coroutines.test runner#2] 메인 종료 실제 사용되는 스레드는 Test worker 스레드 이지만, 테스트 코드에서 실행될 때 Test worker 스레드가 메인 스레드 처럼 동작하기 때문에 메인이라고 말씀해주신 걸까요?? 감사합니다!
-
미해결2시간으로 끝내는 코루틴
suspend 함수에 관해 추가적인 질문 있습니다! (runcatching, Result)
9강을 듣고 이해한 바로는, suspend 함수는 Continuation으로 resumeWith의 Result를 통해 내부적으로 콜백을 진행한다고 이해하였습니다!그렇다면 suspend 함수를 사용할때에는 runCatching을 사용하거나, 반환값을 Result로 묶는것은 불필요한 행위라는 결론을 내렸는데, 맞는 생각인지가 궁금합니다!왜냐면 runCatching과 Result 반환값을 활용하게 된다면, 애초에 suspend로 한번 예외처리를 진행했기에 중복된 작업이라고 생각하였기 때문입니다!팀원들과 부트캠프를 통해 진행한 프로젝트를 개선하고자 하는데, suspend 함수에 runCatching을 사용 후 Result로 반환을 하였어서 불필요한 작업이라고 생각되어 개선하고자 하기에 질문드립니다!긴 글 읽어주셔서 감사합니다!
-
해결됨코틀린 코루틴 완전 정복
job과 코루틴의 관계?
- 학습 관련 질문을 남겨주세요. 질문을 상세히 작성하면 더 좋습니다.- 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 먼저 좋은 강의 감사합니다! 혼자서 다음과 같이 마구마구 찍어보고있었습니다.이때 저희 예상과 다르게 돌아가서 질문을 드립니다.저의 가설로는 "withContext는 코루틴을 생성하지 않고 Context만 바꾸니 코루틴을 제어하고 추적하는데 사용되는 Job은 새로 만들어지지 않을 것이다. 따라서 job1과 job5는 같을 것이다." 이었습니다.하지만 결과는 새로운 job을 만들고 job의 부모에 job1을 연결시키더군요.동일한 코루틴에서 동작하는데 왜 새로운 Job을 만드는 것인가요?fun main() = runBlocking { val job1 = coroutineContext[Job] // 1 coroutineScope { val job2 = coroutineContext[Job.Key] val job3 = launch {} val job4 = launch {} println("job2 = ${job2}") // 2 println("job2 parent = ${job2?.parent}") println("job3 parent = ${job3.parent}") println("job4 parent = ${job4.parent}") } withContext(Dispatchers.Default) { val job5 = coroutineContext[Job.Key] println("job5 = ${job5}") println("job5 parent = ${job5?.parent}") } println("job1 = ${job1}") } // // job5 = DispatchedCoroutine{Active}@4311e223 // job5 parent = BlockingCoroutine{Active}@1c2c22f3 // job1 = BlockingCoroutine{Active}@1c2c22f3coroutineScope도 주석 1, 2 부분이 같은 코루틴이라 job1이랑 job2가 동일하게 나올 거라 생각했는데 다르군요.그렇다면 현재 상황에서 "하나의 코루틴에 여러 개의 job(?)을 가진 것 아닌가? 이러면 job으로 코루틴을 제어할 수 있나?" 라는 의문이 듭니다. job과 코루틴의 관계가 헷갈립니다😱
-
해결됨코틀린 코루틴 완전 정복
코루틴의 blocking I/O작업 처리
- 학습 관련 질문을 남겨주세요. 질문을 상세히 작성하면 더 좋습니다.- 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.궁금한점JDBC, File I/O와 같은 블로킹 I/O작업들은 코루틴에서 수행시 스레드를 반납하지 않는걸로 알고있습니다!그렇다면 대부분의 작업이 JDBC를 통한 RDB조회라면 코루틴을 통해서 크게 가져갈 수 있는 이점은코드의 간결함구조화에서 나오는 장점예외처리작업 제어이정도 되고, 이러한 환경에서는 스레드 반납을 통한 이점은 아쉽지만 크게 못챙겨가는 걸까요?
-
해결됨코틀린 코루틴 완전 정복
KTOR Server 에서 delay
- 학습 관련 질문을 남겨주세요. 질문을 상세히 작성하면 더 좋습니다.- 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 안녕하세요, coroutine 강의를 듣고 ktor server 공부를 하는 중에 delay 관련 질의가 생겨 글 남깁니다. delay 의 경우 coroutine 이 스레드를 양보하고, 일정 시간 후에 다시 스레드가 비어있으면 점유하는 형식으로 진행될텐데, 아래와 같은 경우 delay 이후 코드가 실행되지 않습니다. 사용자 → KTOR Server → suspend function call → loop { logic → 너무 많은 동작을 제한하기위한 delay } ktor 는 기본적으로 요청이 IO Dispatcher 를 사용하는 것 같은데, coroutine 에서 delay 이후 기능이 동작하지 않는 것에 대한 이유가 있을까요..? (강의랑 무관한 내용이라 죄송합니다 ㅠ.ㅠ) /* Routing.kt */ fun Application.configureRouting(searcher: BaseSearcher) { routing { post("/search") { val params = call.receive<Map<String, String>>() searcher.logging("Received POST request with params: $params") val result: List<BaseDTO> = searcher.search(params) searcher.logging("POST Result: $result") call.respond(HttpStatusCode.OK, mapOf("result" to result)) } get("/") { call.respondText("Hello World!") } } } /* Searcher.kt */ /** * 함수 이름 : search * 내용 설명 : 입력된 map<string, string> param 을 바탕으로 요청 전송 및 응답 반환 */ override suspend fun search(searchParam: Map<String, String>): List<SimpleSearchLandResultDTO> { // 별도의 Job 으로 분리해서 오류시 상위 전파 제한 return HttpClient(CIO).use { client -> val parseResultLst: MutableList<SimpleSearchLandResultDTO> = mutableListOf() try { val initRequestResultDto: SimpleSearchResultDTO = sendFormedRequest(client, SearcherConst.URL_MAIN_PAGE, false) // 기본 페이지 요청이 성공했을 때 다음 요청을 진행 if (initRequestResultDto.isSuccess) { val mutableSearchParam = searchParam.toMutableMap() delay(300) while (true) { val eachPageSearchResultDto: SimpleSearchResultDTO = sendFormedRequest(client, makeGetUrl(mutableSearchParam), true) // 실패한 경우 종료 if (!eachPageSearchResultDto.isSuccess) { logging("[search] 조회 중 오류가 발생하였습니다.") break } // 결과가 빈 경우도 종료 else if (eachPageSearchResultDto.landSearchResultLst.isEmpty()) { break } // 결과가 있는 경우엔 전부 더해줌 parseResultLst.addAll(eachPageSearchResultDto.landSearchResultLst) logging("[search] result(${eachPageSearchResultDto.landSearchResultLst[0].currentPage} : ${eachPageSearchResultDto.landSearchResultLst}") // 마지막 페이지인 경우 종료 if (eachPageSearchResultDto.landSearchResultLst[0].currentPage == eachPageSearchResultDto.landSearchResultLst[0].maxPage ) { break } else { // 다음 페이지 수집 진행 mutableSearchParam["currentPage"] = (eachPageSearchResultDto.landSearchResultLst[0].currentPage + 1).toString() delay(300) } } } } catch (e: Exception) { logging("[search] search 함수 중 오류가 발생하였습니다. param: $searchParam, exception: $e") } logging("[search] Result : $parseResultLst") // parseResultLst 반환 parseResultLst } } private suspend fun sendFormedRequest(client: HttpClient, url: String, isResultNeed: Boolean): SimpleSearchResultDTO { return try { val response = client.get(url) { headers { append(HttpHeaders.Cookie, cookie.toCookieString()) append(HttpHeaders.Accept, SearcherConst.DEFAULT_HTTP_ACCEPT) append(HttpHeaders.AcceptEncoding, SearcherConst.DEFAULT_HTTP_ACCEPT_ENCODING) append(HttpHeaders.Connection, SearcherConst.DEFAULT_HTTP_CONNECTION) append(HttpHeaders.AcceptLanguage, SearcherConst.DEFAULT_HTTP_ACCEPT_LANGUAGE) append(HttpHeaders.UserAgent, SearcherConst.DEFAULT_HTTP_USER_AGENT) } } cookie.putAll(response.headers[HttpHeaders.SetCookie]?.split(";")?.map { it.split("=") }?. filter { it.size == 2 }?.filter { it[1] != "/" && it[1].isNotEmpty() }?.associate { it[0] to it[1] } ?: mapOf()) if (response.status != HttpStatusCode.OK) { SimpleSearchResultDTO(false) } else { SimpleSearchResultDTO(true, if(isResultNeed) parseData(response.bodyAsText()) else mutableListOf()) } } catch(e: Exception) { logging("[sendFormedRequest] Error : $e", Level.ERROR) SimpleSearchResultDTO(false) } }
-
해결됨코틀린 코루틴 완전 정복
CoroutineDispatcher(Default, IO)의 limitedParallelism 관련 질문
안녕하세요. 강사님코루틴 강의를 1번 완강하고, 최근에는 전체적으로 강의를 복습을 하고 있습니다.복습을 하다가 CoroutineDispatcher의 limitedParallelism 에 대해 몇가지 궁금한 점이 생겨서 질문을 남기게 됐습니다.Dispatchers.Default 관련Dispatchers.Default의 스레드풀 수를 넘어서는 숫자 혹은 스레드풀 수에 딱 맞게 스레드 수를 지정하여 limitedParallelism 함수를 실행하는 경우,Dispatchers.Default의 모든 스레드들은 제가 지정한 해당 작업을 처리하기 위해 계속 작업을 하고, 해당 작업이 시작된 이후에 Dispatchers.Default로 지정하여 실행한 코루틴 작업들은 제가 지정한 작업이 끝나기 전까지는 모두 대기하게 되는 것인가요??예를 들어, CPU 코어가 4개인 컴퓨터라면 Dispatchers.Default의 스레드 풀에 들어있는 스레드 수는 4개가 될테고, 해당 상황에서 Dispatchers.Default.limitedParallelism(4) 혹은 스레드가 몇개 있는지 몰라 Dispatchers.Default.limitedParallelism(8) 이렇게 지정하는 경우에아래 코드를 기준으로 하면 제가 먼저 시킨 작업(superCpuIntensiveTask())이 끝나기 전에는 lightCpuIntensiveTask()는 실행되지 않는 것일까요?(※ 멀티 스레드 작업이기 때문에 아래의 lightCpuIntensiveTask()가 먼저 실행될 가능성도 있지만 아주 재수가 나쁘게 superCpuIntensiveTask()가 먼저 실행이 된다면 어떻게 되는지가 궁금합니다)// CPU 코어가 4개인 컴퓨터 fun main() = runBlocking { launch(Dispatchers.Default.limitedParallelism(8)) { superCpuIntensiveTask() } launch(Dispatchers.Default) { lightCpuIntensiveTask() } println("Done") } 1번과 비슷한 질문입니다. CPU 코어가 4개인 컴퓨터에서 Dispatchers.Default.limitedParallelism를 여러번 사용한 경우, 코드상으로 보면 사용해야 하는 스레드의 수가 전체 스레드풀 수를 넘어서는 숫자가 되는데 이 경우에는 어떻게 스레드를 나눠서 사용하는 걸까요 ?// CPU 코어가 4개인 컴퓨터 fun main() = runBlocking { launch(Dispatchers.Default.limitedParallelism(3)) { superCpuIntensiveTask() } launch(Dispatchers.Default.limitedParallelism(3)) { superCpuIntensiveTask2() } launch(Dispatchers.Default.limitedParallelism(2)) { CpuIntensiveTask() } println("Done") }Dispatchers.IO 관련Dispatchers.IO.limitedParallelism를 사용하면 새로운 Thread 집합을 만든다고 말씀해주셨습니다. 그림에서 표현해주신 것처럼 기존에는 개별로 존재하는 Thread들을 새로 그룹으로 묶어낸다고 이해를 하면 되는 것일까요 ?? Dispatchers.IO.limitedParallelism으로 묶여있던 Thread들은 해당 코루틴이 끝나면 다시 그룹이 풀리는 것일까요 ??만약에 Dispatchers.IO.limitedParallelism를 많이 사용하여 이미 기존의 스레드들 모두가 집합으로 구성이 되어있는 경우에는 신규로 집합을 만들 수가 없는 경우에는 해당 Dispatchers.IO.limitedParallelism 요청이 어떻게 되는지 궁금합니다.limitedParallelism의 Thread 수 지정해당 코드와 같이 Dispatchers.Default.limitedParallelism(4) Thread 수를 지정해야 할때, 어떤 기준으로 어떻게 Thread 수를 지정해야 좋을까요 ?? 강사님만의 팁이 있으시면 공유가 가능하실까요??어떻게 수를 정해서 넣어야 할지 감이 잘 잡히지 않습니다. 😢1번과 관련된 질문입니다. Thread 수를 지정할 때 현재 Thread Pool에 존재하거나 남아있는 쓰레드가 몇개인지 충분히 고려를 하면서 코드를 짜야할까요 ??실수로 스레드 풀의 전체 Thread 수를 넘어선 요청을 하게 되면 어떻게 되는지 궁금합니다. 질문이 많아서 정말 죄송합니다. 🙇♂🙇♂🙇♂
-
해결됨코틀린 코루틴 완전 정복
suspend 문의 드려요
- 학습 관련 질문을 남겨주세요. 질문을 상세히 작성하면 더 좋습니다.- 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 아무리 생각해도 코루틴 안에서 사용하는 코루틴 안의 delay나 await 등 점유 해제 가능한 fun들을 코드 중복을 피하기 위해 따로 빼놓은 delay나 join await를 포함한 코루틴용 fun의 키워드 같은데 구글링해서 보면 마치 delay나 await, join 이 포함된 fun 은 무조건 suspend를 사용하고 점유 해제 되도록 한다고 설명한데가 많네요. 결론은 suspend 자체가 점유 해제 하고 resume을 시켜주는 키워드가 아닌 것 같은데 제가 이해한게 맞나요?
-
해결됨코틀린 코루틴 완전 정복
스레드 양보 예제 + 코루틴/멀티스레드 사용 예시 질문
- 학습 관련 질문을 남겨주세요. 질문을 상세히 작성하면 더 좋습니다.- 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.section10의 code4/Code10-4에서 보면코드가 아래와 같이 되는데package section10.code4 import kotlinx.coroutines.* fun main() = runBlocking<Unit> { val startTime = System.currentTimeMillis() repeat(10) { repeatTime -> launch { Thread.sleep(1000L) // 1초 동안 스레드 블로킹(코루틴의 스레드 점유 유지) println("[${Thread.currentThread().name}] 작업 실행 ") println("[${getElapsedTime(startTime)}] 코루틴${repeatTime} 실행 완료") } } } fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"보통 이런 코드는 이렇게 멀티스레드로 처리하지 않나요..?import java.util.concurrent.Callable import java.util.concurrent.Executors fun main() { val startTime = System.currentTimeMillis() val es = Executors.newFixedThreadPool(10) val callTasks = mutableListOf<Callable<Int>>() repeat(10) { repeatTime -> val callTask = Callable { println("[${Thread.currentThread().name}] 작업 실행 ") return@Callable repeatTime } callTasks.add(callTask) } val results = es.invokeAll(callTasks) // 결과 출력 results.forEach { future -> println("Result: ${future.get()}") } println("[${getElapsedTime(startTime)}] 실행 완료") es.close() } fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"음.. 그리고 스레드 1개를 만들어서 run을 시키면 1MB정도의 메모리 비용이 발생하고 context switch도 일어나지만, 코루틴은 훨씬 더 값싸다고 알고있습니다추가로 아직 r2dbc처럼 비동기 트랜잭션 처리 등.. 이게 지원이 좀 미약하다고 알고있습니다. 서버의 작업은 대체로 CPU를 사용하는 부분이 그렇게 많이 없고 DB에 쓰고 값을 가져오는 동기화 코드, 순차처리 작업이 많은걸로 알고 있습니다.그럼 언제 멀티스레드를 사용하는게 좋고, 언제 코루틴을 사용하는게 좋을까요?
-
해결됨코틀린 코루틴 완전 정복
coroutineScope 관련 질문 및 실제 사용 사례에 대한 질문
안녕하세요. 강사님 강사님 덕분에 코루틴에 대한 이해도가 많이 높아져서, 최근 코루틴을 활용한 비동기 서버 구현에 대해서 재밌게 개발을 하고 있습니다. (코루틴이 재미는 있는데, 비동기라는 개념 때문에 너무 어려워서 머리가 아프네요 😢) spring webflux와 코루틴을 활용한 서버 개발을 하다보니, 자연스럽게 suspend 키워드가 많이 사용되고 일시 중단 함수에 대해서 조금 더 높은 이해도가 필요해서 이에 대해서 몇가지 질문을 하려고 합니다. 1.저는 강사님의 일시 중단 함수 관련 강의를 듣고 일시 중단 함수란 그냥 일시 중단 지점을 포함할 수 있는 특이한 함수,suspend 함수에서 코루틴을 사용하기 위해서는 coroutineScope을 사용하자이렇게 이해를 했어서 다음과 같이 코드를 짰습니다.class SuspendRequestTest { @Test fun suspendRequestTest() = runBlocking { val startTime = System.currentTimeMillis() // 시작 시간 기록 println("suspendRequest start") anotherSuspendFunction1() // suspend function 1 호출 anotherSuspendFunction2() // suspend function 2 호출 println("suspendRequest end") val endTime = System.currentTimeMillis() // 종료 시간 기록 println("suspendRequest elapsed time: ${endTime - startTime} ms") // 경과 시간 출력 } private suspend fun anotherSuspendFunction1() = coroutineScope { println("anotherSuspendFunction1 start") launch { println("anotherSuspendFunction1 extra logic start") delay(1000) println("anotherSuspendFunction1 extra logic end") } println("anotherSuspendFunction1 end") } private suspend fun anotherSuspendFunction2() = coroutineScope { println("anotherSuspendFunction2 start") launch { println("anotherSuspendFunction2 extra logic start") delay(1000) println("anotherSuspendFunction2 extra logic end") } println("anotherSuspendFunction2 end") } }// 실행 로그 suspendRequest start anotherSuspendFunction1 start anotherSuspendFunction1 end anotherSuspendFunction1 extra logic start anotherSuspendFunction1 extra logic end anotherSuspendFunction2 start anotherSuspendFunction2 end anotherSuspendFunction2 extra logic start anotherSuspendFunction2 extra logic end suspendRequest end suspendRequest elapsed time: 2037 ms제 예상대로라면 1초가 살짝 넘는 시간으로 작업이 완료되어야 하는데, 해당 작업은 2초가 걸리는 작업이었습니다. (로그도 항상 1번이 먼저 나타납니다.)1-1) 혹시 coroutineScope은 내부의 코드가 완료되기 전까지는 다음으로 넘어가지 않는 Blocking 속성을 가지는 함수일까요 ?1-2) supervisorScope도 coroutineScope 처럼 내부의 코드가 완료되기 전에는 다음으로 넘어가지 않는다고 알면 될까요?1-3) 일시 중단 함수가 여러 일시 중단 함수들을 내부 로직으로 가지는 경우, 순차적으로 각각의 일시 중단 함수가 끝나야지만 다음 일시 중단 함수가 실행되는 걸까요 ?2.제가 실제 코루틴 사용 사례 및 코드를 많이 보지 못해서, 어떻게 쓰는게 좋은 케이스 인지 이해도가 낮은 것 같습니다. 보통 coroutineScope 혹은 supervisorScope함수들은 어떤 경우에 어떤 목적을 위해 주로 쓰이는 걸까요 ??coroutineScope의 속성이나 특징에 관해서 추가적으로 제가 알아야 하거나 참고하면 좋을 자료가 있을까요?? 😊
-
해결됨코틀린 코루틴 완전 정복
Coroutine 취소 시점 체크
isActive라는 확장 프로퍼티를 이용해서 일시 중단 시점을 만들지 않고도 확인할 수 있다는 내용은 이해했습니다.다만 본 강의의 예시에서는 while문을 통해서 계속해서 isActive를 확인해서 취소된 걸 곧바로 알 수 있었지만,만약 실무에서 coroutine내에 어떤 로직들이 길게 적혀 있다면, 한 줄 한줄 마다 if 문을 통해 isActive를 확인해야 하는 코드가 들어가야 하는 걸까요? 아니면 조금 비효율적인 것을 감안하고 yield 같은 함수를 중간 중간에 넣어두어야 하는 걸까요?
-
해결됨코틀린 코루틴 완전 정복
spring web mvc 환경에서 coroutine을 사용해보신 경험이 있으신지 궁금합니다.
안녕하세요 강사님, 강의 잘 들었습니다개인적으로 코루틴에 관해서 정말 많이 배웠습니다. 모든 걸 다 소화하지는 못했지만, 필요할 때마다 돌아와서 정독하면 충분히 필요한 부분을 얻어갈 수 있다는 생각이 드네요. 좋은 강의 감사드립니다.몇가지 궁금한 부분이 있어 질문드립니다.사내에서 사용하는 기술스택이 spring web mvc + JPA + feignClient인데 혹시 이와 유사한 환경에서 코루틴을 적용해보신 경험이 있으실까요?특히 제가 기대했던 부분은 IO작업에 관해 요청을 보내고 스레드를 점유하지 않음으로써 리소스를 효율적으로 사용하는 것(즉 처리량을 증가시키는 것)을 기대했었는데 아무래도 JPA나 feignClient나 응답이 올때까지 대기하는 구조로 되어 있더라구요ㅠㅠ.. 드라마틱한 성과를 기대하기는 조금 힘들어보이긴하네요 혹시 관련해서 유사한 경험이 있으신지 싶어서 의견을 묻고자 여쭤봅니다.코루틴을 사용중인 환경에서 rps가 급증하면 어떤식으로 흘러갈지 궁금합니다. 스레드가 고갈될 것 같은데, 자연스럽게 dispatcherIO등의 스레드가 새로 생성되나요?- 그렇다고 하면 메모리가 고갈될 것 같은데, 코루틴을 사용할때는 결과적으로 메모리 기준으로 스케일아웃을 걸어야할지? 등이 궁금하네요.
-
해결됨코틀린 코루틴 완전 정복
코루틴이 멀티스레드의 단점을 해결했다는 부분에 대해 질문드립니다.
안녕하세요? 강의 잘 듣고 있습니다. 코루틴이 멀티스레드의 단점을 해결했다고 말씀해주셨는데요, 관련해서 약간 정리가 되는 듯 안되는듯 하여 질문드립니다.1. 우선 아래의 정리가 맞는지 여쭤보고 싶습니다.멀티 스레딩의 문제점은 결국 blocking이고 이 blocking을 해결하기 위해 코루틴을 도입했음코루틴은 스레드를 점유하는 형태로 동작하므로, 반대로 코루틴이 blocking될때 스레드를 점유하지 않음으로써 다른 코루틴이 해당 스레드를 점유하게 되고 결과적으로 스레드가 blocking되는 일이 없어진다. 2. 그런데 blocking이 되는 현상이 언제발생하나요?강의에서 말씀해주신 내용에 따르면, 다른 스레드 혹은 코루틴의 결과가 필요할 때 blocking되는 상황에 놓여지는 것 같은데 맞을까요?결국 그렇다고하면 이전 코드의 완료를 보장하는, 그러니까 sync한 방식으로 코딩을 해야할 때 스레드가 놀지 않으면서 & completableFuture처럼 콜백지옥이나 예외처리가 어렵지 않게 하는 것이 코루틴의 장점이 맞을까요? 3. 일반적인 IO상황도 위에서 얘기한 blocking이 맞을까요?다르게 말하면, Dispatcher IO에서 [요청을 보내고 기다려야만 하는 상황]에서도 코루틴은 스레드의 점유권을 내려놓음으로써 해당 스레드가 다른 작업을 처리할 수 있게 되는걸까요?예를 들면, A스레드가 코루틴의 DIspatcher IO에 의해 관리되는 IO전용 스레드고 IO스레드는 해당스레드하나만 존재할때(가용가능한 다른 스레드가 없는 상황) c코루틴은 서버에 호출을 보내서 4초가 걸리고, d코루틴은 서버에 호출을 보내서 5초가 걸리면 A스레드에서 c코루틴과 d코루틴을 병렬적으로 처리할 수 있는건가요? 단순히 다른 스레드를 하나 생성해서 두가지 작업을 다 맡겼더라면 해당 스레드에서 4초 + 5초해서 9초가 걸렸을텐데, 코루틴기반의 A스레드에서는 약 5초정도밖에(조금 더 길수는 있겠지만) 안걸리는 게 맞을까요? 4. 3번에 이어지는 질문인데요, 만약 3번이 맞다고 하면 IO작업의 응답이 왔을 때 콜백같은 게 적용이 되어서 Dispatcher에 새로운 작업으로 추가되는걸까요?그러면, IO요청을 보낸 스레드와 IO응답을 처리하게 되는 스레드가 왠지 다를 수도 있을 것 같은데 맞을까요? 3번이 맞다고 하면, 코루틴은 아주 아름다운 것일 것 같은데 굉장히 설레네요 ㅎㅎ좋은 강의 감사합니다.
-
해결됨코틀린 코루틴 완전 정복
Dispatcher.IO의 동작원리
안녕하세요! 강의 재밌게 보고 있습니다! ㅎㅎ 코루틴을 공부하면서 항상 의문이던 부분이였는데 Dispatcher.IO가 Http Request 같은 IO 작업에서 어떤 원리로 Dispatcher.Default보다 더 효율적인걸까요? 내부 스레드선언이 더 많아서 Default보다 더 자주 코루틴 컨텍스트 스위칭이 되는걸까요?
-
해결됨코틀린 코루틴 완전 정복
실무에서 runBlocking 와 CoroutineScope 실무 사용에 대해
실무에서 코루틴을 사용해야할 때runBlocking 으로 코루틴 영역을 생성해야 할지 CoroutineScope로 생성해야 할지 또 어떻게 코루틴을 활용해야할지 감이 살짝 오시 않습니다.물론 호출부의 스레드를 블럭킹해야 한다면 runBlocking 일 것 같지만 보통 이렇게 사용한다라는 지향점이 궁금합니다. 실무에서 사용하기 위해 추천할만한 깃헙 레파지토리나 베스트프랙티스가 있을까요? - 학습 관련 질문을 남겨주세요. 질문을 상세히 작성하면 더 좋습니다.- 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.
-
해결됨코틀린 코루틴 완전 정복
Code3-6에서 imageProcessingDispatcher가 inline으로는 동작하지 않는 이유가 궁금합니다
안녕하세요. 기초적인 질문 같지만, 코루틴을 처음 사용하는 입장에서 imageProcessingDispatcher를 인라인으로 넣을 수 없는 이유가 궁금합니다. 직접 테스트했을 때,launch(Dispatchers.Default.limitedParallelism(2)) { //... }와 같은 코드는 예상한대로 동작하지 않고, 머신 processor만큼을 사용하는 것으로 보이는데, 그 이유가 뭘까요?
-
해결됨2시간으로 끝내는 코루틴
간단 질문.. join() vs delay()
예제를 실행하면서 job이 종료되기까지 join()으로 기다리는 방법이 있고, 스코프를 다른곳으로 보내서 메인스레드가 더 빨리 종료되게 하지 않기 위해 자식스코프 또는 main스레드 내부의 Root 코루틴스코프의 실행시간보다 delay를 길게 주는 방법이 있는것같은데요아래 1번, 2번 방법 중에 어떤 차이가 있고, 코루틴을 현업에서 쓸 때는 어떤 방법으로 보통 사용하게되나요?그리고 강의를 아직 다 보지는 않았는데.. RxJava, WebFlux, Virutal Thread, Coroutine 등을 어떤 영역에서 활용하는지 궁금합니다Network, File I/O, DB CRUD, External API call, etc...그리고 음.. 2022년도쯤에는 비동기트랜잭션이 하이버네이트쪽에서 잘 지원 안해줘서 r2dbc를 사용하다가 취소한 곳이 있다고도 얼핏 들은것같은데 현재는 어떤지 위에 활용처 질문과 함께 알려주시면 감사하겠습니다!fun test(): Unit = runBlocking { val job1 = CoroutineScope(Dispatchers.Default).launch { delay(1_000L) printWithThread { "Job 1" } } val job2 = CoroutineScope(Dispatchers.Default).launch { delay(1_000L) printWithThread { "Job 2" } } // 1번 방법 job1.join() job2.join() // 2번 방법 delay(2_000L) }
-
해결됨코틀린 코루틴 완전 정복
공유 스레드 풀 질문드려요!
섹션4. CoroutineDispatcher 에서 미리 정의된 공유스레드 풀 내에 Dispatchers.Defualt 는 프로세서 개수(최하 2), Dispatchers.IO (64or프로세서 개수 중의 큰 수) 의 개수만큼의 스레드가 할당되는건가요? - 학습 관련 질문을 남겨주세요. 질문을 상세히 작성하면 더 좋습니다.- 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.
-
해결됨코틀린 코루틴 완전 정복
코루틴 이름 출력관련해서 질문이 있습니다!
println("[${Thread.currentThread().name}] 코루틴 실행2") 위 코드 실행할 때 실행결과가 아래와 같이 나오는데 @coroutine#1 어떻게 이렇게 코루틴 이름까지 같이 나오게 할 수 있나요?! [출력 결과] [MyThread1 @coroutine#1] 코루틴 실행 2
-
해결됨코틀린 코루틴 완전 정복
coroutineScope에 대해 질문 있습니다.
suspend fun searchByKeyword(keyword: String): Array<String> = coroutineScope { val dbResultsDeferred = async { searchFromDB(keyword) } val serverResultsDeferred = async { searchFromServer(keyword) } return@coroutineScope arrayOf(*dbResultsDeferred.await(), *serverResultsDeferred.await()) }안녕하세요 "일시 중단 함수의 사용" 학습 중 나온 코드에 대해 질문 드립니다.강의에서는 "coroutineScope을 사용하면, 일시중단 함수 내부에 coroutineScope 객체를 만들 수 있다."라고 하셨는데, 이 부분이 이해가 잘 안갑니다.먼저 coroutineScope {}를 선언하고, async 비동기 작업 -> delay 일시중단 순으로 진행되는데 일시중단 함수 내부에 coroutineScope 객체를 만들 수 있는 것이 이해가 잘 가지 않습니다.제가 정리하기로는, "coroutineScope을 사용하면, 일시중단 함수 내부에 coroutineScope 객체를 만들 수 있다."라기 보다는 위 그림처럼 "하나의 coroutineScope에 2개의 비동기 작업과 각각의 일시중단 함수를 포함하는 것"으로 받아들여지는데 제가 어느 부분을 놓치고 있는건지 잘 모르겠습니다. 감사합니다. ^^