Coroutines와 Channels 튜토리얼 - 2. Blocking Requests

2023. 5. 20. 21:02·공식 문서 번역/Coroutines 공식 문서
목차
  1. Blocking 요청들
  2. Task 1
반응형

Blocking 요청들

GitHub에 HTTP 요청을 하기 위해 Retrofit 라이브러리를 사용할 것이다. 주어진 조직에 속한 저장소 목록과 각 저장소의 기여자 목록을 요청할 수 있다.

 

interface GitHubService {
    @GET("orgs/{org}/repos?per_page=100")
    fun getOrgReposCall(
        @Path("org") org: String
    ): Call<List<Repo>>

    @GET("repos/{owner}/{repo}/contributors?per_page=100")
    fun getRepoContributorsCall(
        @Path("owner") owner: String,
        @Path("repo") repo: String
    ): Call<List<User>>
}

 

이 API는 주어진 조직의 기여자 목록을 가져오기 위해 loadContributorsBlocking() 함수에서 사용된다. 

 

1. src/tasks/Request1Blocking.kt 를 열어 구현체를 보자 :

fun loadContributorsBlocking(service: GitHubService, req: RequestData): List<User> {
    val repos = service
        .getOrgReposCall(req.org)   // #1
        .execute()                  // #2
        .also { logRepos(req, it) } // #3
        .body() ?: emptyList()      // #4

    return repos.flatMap { repo ->
        service
            .getRepoContributorsCall(req.org, repo.name) // #1
            .execute()                                   // #2
            .also { logUsers(repo, it) }                 // #3
            .bodyList()                                  // #4
    }.aggregate()
}
  • 먼저 주어진 조직의 저장소 목록을 가져와 repos 리스트 속에 저장한다. 그리고 각 저장소에 대해 기여자들이 요청되고 모든 리스트들이 하나의 최종 기여자 목록으로 합쳐진다.
  • getOrgReposCall() 과 getRepoContributorsCall() 각각은 *Call class의 인스턴스를 반환한다 (#1). 이 시점에는 어떠한 요청도 전송되지 않는다.
  • 그 다음 *Call.execute()이 실행되어 요청이 수행된다 (#2). execute() 은 현재 수행중인 Thread를 Block하는 동기 호출이다.
  • 응답을 받게되면, 결과값이 logRepos() 와 logUsers() 함수들에 의해 로깅된다 (#3). 만약 HTTP 응답이 애러를 가지고 있으면, 애러가 로깅된다.
  • 마지막으로, 필요로 하는 데이터를 가진 응답의 body 부분을 가져온다. 이 튜토리얼에서는 애러가 있는 경우 결과로 빈 리스트를 사용하고 해당 애러를 기록한다 (#4).

 

2. .body() ?: emptyList()를 반복적으로 사용하는 것을 피하기 위해 확장 함수인 bodyList()가 선언된다.

fun <T> Response<List<T>>.bodyList(): List<T> {
    return body() ?: emptyList()
}

 

3. 프로그램을 다시 실행한 후 IntelliJ IDEA의 시스템 출력을 확인해보자. 다음과 같을 것이다.

1770 [AWT-EventQueue-0] INFO  Contributors - kotlin: loaded 40 repos
2025 [AWT-EventQueue-0] INFO  Contributors - kotlin-examples: loaded 23 contributors
2229 [AWT-EventQueue-0] INFO  Contributors - kotlin-koans: loaded 45 contributors
...
  • 각 줄의 첫 항목은 프로그램이 시작된 후 경과된 밀리초를 나타내며, 대괄호 내부에는 Thread의 이름이 있다. 이를 통해 어떤 Thread에서 로딩 요청이 호출되었는지를 확인할 수 있다.
  • 각 줄의 마지막 항목은 얼마나 많은 저장소와 기여자들이 로드되었는지에 대한 실제 메세지이다.

 

이 출력된 로그는 결과값들이 Main Thread에서 로깅 되었다는 것을 나타낸다. 만약 BLOCKING 옵션을 설정한 상태로 코드를 실행하면 윈도우는 멈추며 로딩이 끝날 때까지 입력에 반응하지 않는다. 모든 요청들은 loadContributorsBlocking() 를 호출한 Thread와 동일한 Thread에서 실행되며, 이 Thread는 Main UI Thread(Swing에서는 AWT event dispatching thread이다)이다. 이 Main Thread가 Block되기 때문에 UI가 멈추는 것이다.

 

그림1

기여자들의 리스트가 로드된 후에 결과값은 업데이트 된다.

 

4. src/contributors/Contributors.kt 내부에서 기여자들을 로드하는 방식을 선택하는 책임을 가진 loadContributors() 함수를 찾고, loadContributorsBlocking()이 어떻게 호출되는지 살펴보자.

when (getSelectedVariant()) {
    BLOCKING -> { // Blocking UI thread
        val users = loadContributorsBlocking(service, req)
        updateResults(users, startTime)
    }
}
  • loadContributorsBlocking() 바로 다음에 updateResults()가 호출된다.
  • updateResults() 는 UI를 업데이트 한다, 따라서 이는 언제나 UI Thread에서 호출되어야 한다.
  • loadContributorsBlocking() 또한 UI Thread에서 호출되기 때문에, UI Thread가 Block되며 UI가 멈춘다.

 

Task 1

첫 작업은 작업 도메인에 익숙해질 수 있도록 하는데 도움을 줍니다. 현재, 각 기여자들의 이름은 참여한 모든 프로젝트에 대해 한 번씩 추가 되고 있어, 여러 번 반복되고 있습니다. 각 기여자가 한 번만 추가될 수 있도록 사용자를 합치는 함수인 aggregate()을 구현합니다. User.contributions 프로퍼티는 주어진 유저가 모든 프로젝트에 기여한 총 횟수를 포함해야 합니다. 결과 목록은 기여 횟수에 따라 내림차순으로 정렬 되어야 합니다.

 

src/tasks/Aggregation.kt 를 열어 List.aggregate() 함수를 구현하시오. 유저는 그들의 총 기여 횟수에 따라 정렬되어야 합니다.

 

해당 test/tasks/AggregationKtTest.kt 파일은 기대되는 결과의 예시를 보여줍니다.

 

📖  IntelliJ IDEA의 단축키 Ctrl+Shift+T/⇧ ⌘ T 를 사용해 소스 코드와 테스트용 클래스 사이를 자동으로 이동할 수 있다.

 

이 작업을 구현한 이후에, "kotlin" 조직에 대한 결과 목록은 다음과 유사해야 한다.

 

그림2

 

Task 1 솔루션

더보기

1. 로그인 별로 사용자들을 그룹화하기 위해서는 다른 저장소들에서 이 로그인을 사용하는 모든 경우를 Map으로 반환하는 groupBy() 함수를 사용해야 한다.

2. Map의 각 항목에 대해, 총 기여 수를 세고 주어진 이름과 기여 수의 합을 사용해 User Class의 새로운 인스턴스를 생성한다.

3. 결과 리스트를 내림차순으로 정렬한다.

fun List<User>.aggregate(): List<User> =
    groupBy { it.login }
        .map { (login, group) -> User(login, group.sumOf { it.contributions }) }
        .sortedByDescending { it.contributions }

groupBy() 대신에 groupingBy() 함수를 사용할 수 있다.

 


이 글은 Coroutines 공식 문서를 번역한 글입니다.

 

원문 : Coroutines and channels − tutorial - Blocking requests

원문 최종 수정 :  2022년 8월 19일

 

반응형

'공식 문서 번역 > Coroutines 공식 문서' 카테고리의 다른 글

Coroutines와 Channels 튜토리얼 - 1. 시작하기 전 준비하기  (0) 2023.05.19
IntelliJ IDEA 사용해 Kotlin Flow 디버깅 하기  (0) 2023.05.18
IntelliJ IDEA 사용해서 Coroutine 디버깅 하기  (0) 2023.05.17
Coroutine 공유 상태와 동시성 3편 - Mutex 사용하기, Actors 사용하기  (0) 2023.05.16
Coroutine 공유 상태와 동시성 2편 - Thread-safe한 데이터 구조, 세밀하게 Thread 제한하기, 굵게 Thread 제어하기  (0) 2023.05.15


  1. Blocking 요청들
  2. Task 1
'공식 문서 번역/Coroutines 공식 문서' 카테고리의 다른 글
  • Coroutines와 Channels 튜토리얼 - 1. 시작하기 전 준비하기
  • IntelliJ IDEA 사용해 Kotlin Flow 디버깅 하기
  • IntelliJ IDEA 사용해서 Coroutine 디버깅 하기
  • Coroutine 공유 상태와 동시성 3편 - Mutex 사용하기, Actors 사용하기
심플코드
심플코드
프로그래밍을 어렵지 않게 풀어서 설명하는 기술 블로그
    반응형
  • 심플코드
    심플코드
    심플코드
  • 전체
    오늘
    어제
    • 분류 전체보기 (96)
      • 안드로이드를 위한 Coroutines (2)
      • Unit Testing (19)
      • GitHub Actions (0)
      • 공식 문서 번역 (35)
        • Coroutines 공식 문서 (35)
      • 알고리즘 (7)
        • Kotlin 자료구조 (0)
        • 알고리즘 (7)
        • Kotlin으로 구현하는 자료구조 (0)
      • 코딩 테스트 (0)
      • Deep Learning (0)
      • Machine Learning Math (17)
        • Linear Algebra (17)
      • ML (0)
      • Docker (15)
      • Kubernetes (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • 코틀린 코루틴의 정석 책 출간 소식
  • 인기 글

  • 태그

    numpy
    Coroutines Flow
    도커
    Docker
    코루틴 채널
    Coroutines
    Coroutines Context
    컨테이너
    pytorch
    TensorFlow
    코루틴 Flow
    코루틴
    Coroutines Channel
    Kotlin
    unit test
    junit
    unit testing
    Machine Learning
    coroutine
    mockito
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
심플코드
Coroutines와 Channels 튜토리얼 - 2. Blocking Requests
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.