Skip to main content

Command Palette

Search for a command to run...

동기와 비동기 vs 블락킹과 논블락킹

Published
4 min read
동기와 비동기 vs 블락킹과 논블락킹

더 잘하고 싶은 안드로이드 개발자.

https://github.com/jinukeu

동기와 비동기 vs 블락킹과 논블락킹

참고 자료 1 참고 자료 2 참고 자료 3 참고 자료 4

동기 & 비동기

여러 개의 함수들이 시간을 맞춰서 실행되느냐에 따라 구분

  • 동기
    함수가 두 개 이상 존재할 때, 이 함수들이 작업을 동시에 시작하거나, 끝나는 타이밍을 맞추거나, 하나가 끝나고 다른 하나를 차례로 실행하는 것

  • 비동기
    두 함수는 서로가 언제 시작하고, 언제 일을 마치는지 전혀 신경쓰지 않는 것

블로킹 & 논블로킹

  • 제어권
    자신(함수)의 코드를 실행할 권리 같은 것. 제어권을 가진 함수는 자신의 코드를 끝까지 실행한 후, 자신을 호출한 함수에게 돌려준다.

  • 블로킹
    다른 함수를 호출할 때, 제어권도 아예 함께 넘겨주고 작업이 끝난 후에 돌려받는 방식

  • 논블로킹
    호출할 때 제어권을 넘겨주기는 하지만, 바로 돌려받는다.

요약

동기/비동기 : 시간을 맞추냐, 안맞추냐
블로킹/논블로킹 : 제어권을 넘겨주냐, 안넘겨주냐

백문이 불여일견! 코드로 직접 한번 봐보자!

function employee() {
  for (let i = 1; i < 101; i++) {
    console.log(`직원: 인형 눈알 붙히기 ${i}번 수행`);
  }
}

function boss() {
  console.log('사장: 출근');
  employee();
  console.log('사장: 퇴근');
}

boss();

사장: 출근 직원: 인형 눈알 붙히기 1번 수행 직원: 인형 눈알 붙히기 2번 수행 ... 직원: 인형 눈알 붙히기 100번 수행 사장: 퇴근

  • 블락킹일까? 논블락킹일까?
  1. boss()함수 내에서 employee()함수가 실행되면 boss()함수의 제어권employee()로 넘어간다.

  2. employee()함수는 종료된 이후에 제어권을 다시 boss()함수로 넘겨준다.
    -> 음! 제어권을 넘겨주고 다시 받았으니 블락킹 이구나!

  • 동기일까? 비동기일까?
  1. boss()함수가 실행되다가 employee()함수가 실행된다.

  2. employee()함수가 종료된 이후에 boss()함수가 마저 실행되고 종료된다. -> 음! 두 개의 함수가 순차적으로 실행되니 동기 이구나!

즉 위 코드는 동기-블락킹이다.

다음 문제~!

int main() {
    Future ft = asyncFileChannel.read(~~~); //논블락킹 함수 - 대략 60분 동안 실행된다고 가정

    while(!ft.isDone()) {
        // isDone()은 asyncChannle.read() 작업이 완료되지 않았다면 false를 바로 리턴해준다.
        // isDone()은 물어보면 대답을 해줄 뿐 작업 완료를 스스로 신경쓰지 않고,
        // isDone()을 호출하는 쪽에서 계속 isDone()을 호출하면서 작업 완료를 신경쓴다.
        // asyncChannle.read()이 완료되지 않아도 여기에서 다른 작업 수행 가능 
    }
}
// 작업이 완료되면 작업 결과에 따른 다른 작업 처리

그냥 블로그에서 퍼온 코드이다...! 주석을 자세히 읽으면 동기/비동기, 블락킹/논블락킹을 판단할 수 있다.

asyncFileChannel.read()함수는 논블락킹 함수이다. 즉 main() 함수는 제어권을 asyncFileChannel.read()함수로 넘겨준 뒤 바로 돌려받는다.

isDone()은 단순히 asyncFileChannel.read()함수의 작업이 완료되었는지 파악하는 함수이다. isDone()true일 때, 즉 asyncFileChannel.read()가 종료된 이후에 main()함수의 나머지 부분이 실행되므로 동기이다.

-> 정답! 논블락킹-동기

선생님, 다음 문제는 블락킹-비동기 예제 인가요?? ㅋㅋ
아쉽게도 블락킹-비동기에 대한 예제 코드는 ... 없다 ... ! 대신 언제 블락킹-비동기가 발생하는지 서술하겠다.

Asynchronous Non-Blocking 모델 중에서 Blocking 으로 동작하는 작업이 있는 경우 의도와 다르게 Asynchronous Blocking으로 동작할 때가 있다고 한다.

대표적인 예로는 Node.js와 MySQL을 함께 사용하는 경우이다. Node.js는 비동기로 작업하려 하지만 MySQL 드라이버가 Blocking 방식으로 동작하므로 어쩔 수 없이 Asynchronous Blocking 방식으로 동작하게 된다.

후후 ... 분명 블락킹/논블락킹, 동기/비동기에 대한 설명을 들으면서 블락킹 == 동기, 비동기 == 논블락킹 아냐? 라는 생각을 했을 것이다 ... ! 하지만 위 예시를 보면 전혀 아니라는 것을 알 수 있다!

int main() {
    Future ft1 = asyncFileChannel.read(A); //논블락킹 함수 - 5분 동안 실행
    Future ft2 = asyncFileChannel.read(B); //논블락킹 함수 - 10분 동안 실행
}

위 코드는 ... 어디보자 asyncFileChannel.read(A), asyncFileChannel.read(B) 모두 논블락킹 함수이고 2개의 함수는 시간에 맞춰 실행되지 않으므로 비동기 ... !
-> 정답! 논블락킹-비동기!

아래는 실제 프로젝트에서 동기 처리를 해주지 않아 생긴 문제이다.

Access Token 갱신 요청이 동시에 2번 발생하면서 생긴 문제

🚨 Issue

okhttp3.Authenticator를 사용하여 서버에서 내려온 HTTP Status Code401인 경우 자동으로 Access Token 갱신 요청을 하도록 만들어놨습니다.

  1. 유저의 Access Token이 만료된 상태에서 Access Token이 필요한 api 2개를 비동기 호출

  2. okhttp3.Authenticator에 의해 Access Token Refresh Api가 2번 비동기 호출

  3. 2개의 Access Token Refresh Api(ㄱ, ㄴ)Body에는 A Refresh Token 값이 들어감

  4. ㄱ Api 호출에서 A Refresh Token이 갱신되어 B Refresh Token으로 변경됨

ㄱ Api Http Body서버 DB에 저장된 유저의 Refresh Token
요청refresh : A Refresh TokenA Refresh Token
처리 완료B Refresh Token
  1. ㄴ Api가 호출되지만 이미 ㄱ Api 호출에서 서버 DB에 저장된 유저의 Refresh Token 값이 바뀌었기 때문에 토큰 갱신 실패
ㄴ Api Http Body서버 DB에 저장된 유저의 Refresh Token
요청refresh : A Refresh TokenB Refresh Token
처리 실패A Refresh Token invaild

Solution

Api 호출을 동기 처리하여 문제를 해결했습니다.

//ViewModel.kt

// 서버에서 강의 평가의 통합 정보를 불러온다. 요청이 성공했을 경우 onSuccess()를 실행한다.
suspend fun fetchLectureIntegratedInfo(onSuccess: () -> Unit) {
        val response = lectureInfoRepository.getLectureDetailInfo(pageViewModel.lectureId)
        when {         
            response.isSuccessful -> {
                response.body()?.data?.let { data ->
                    _lectureDetailInfoData.value = data
                    onSuccess()
                }
            }
            else -> {
                handleError(response.code())
            }
        }
    }

// 서버에서 강의평가 또는 시험정보 리스트를 불러온다.
fun fetchLectureList() {
        if(pageViewModel.page.value!! == LAST_PAGE)
            return
        when (_writeBtnText.value) {
            R.string.write_evaluation -> getEvaluationList()
            else -> getExamList()
        }
    }
//Fragment.kt
lifecycleScope.launch {
    lectureInfoViewModel.fetchLectureIntegratedInfo {
        lectureInfoViewModel.fetchLectureList()
   }
}

More from this blog

단위테스트 2장 정리

단위 테스트의 정의에는 많은 늬앙스가 있다. 크게 고전파, 런던파로 나뉜다. 고전파: 모든 사람이 단위 테스트와 테스트 주도 개발에 원론적으로 접근하는 방식 런던파: 런던의 프로그래밍 커뮤니티에서 시작 단위 테스트의 정의 단위 테스트는 작은 코드 조각을 검증하고 빠르게 수행하고 격리된 방식으로 처리하는 자동화된 테스트다. 격리 문제에 대한 런던파의 접근 코드 조각을 격리된 방식으로 검증한다는 것은 무엇을 의미할까? 런던파에서는 테스트 ...

Sep 3, 20243 min read

단위 테스트 1장 정리

단위 테스트 1장 정리 내용입니다. 단위 테스트에 시간을 투자할 때는 항상 최대한 이득을 얻도록 노력해야하며, 테스트에 드는 노력을 가능한 줄이고 그에 따르는 이득을 최대화해야 한다. 이 책에서 다루는 내용은 비용 편익 분석 방법을 배우고 특정 상황에서 적절한 테스트 기술을 적용할 수 있다. 또한 공통적인 안티 패턴을 피하는 방법도 배운다. 단위 테스트의 목표 단위 테스트의 목표는 무엇인가? 프로젝트의 지속 가능한 성장을 가능하게 하는 것이다...

Aug 27, 20242 min read

23년 하반기 회고

23년 상반기 회고에서 이어지는 글이다. 8 - 9월 이력서 제출 그리고 ... 이력서와 포트폴리오를 만들었다. 꽤나 잘 만들었다고 생각했다. 개발자 지인들의 첨삭, 인프런 멘토링, 유료 이력서 첨삭 서비스를 받으며 칭찬을 꽤 받았기 때문이다. 내가 보기에도 괜찮은 것 같고 ... 다른 사람들이 보기에도 괜찮다고 했으니 서류 합격률은 꽤 높을거라 생각했다. 50개의 서류를 넣은 결과, 3번의 서류 합격 그리고 단 한 곳에서만 최종합격했다. (최...

Jan 1, 20243 min read
23년 하반기 회고

[Android] Compose 수명 주기, 부수효과

수명 주기 개요 컴포지션은 UI를 기술하는 컴포저블의 트리 구조이다.컴포지션은 초기 컴포지션을 통해서만 생성되고 리컴포지션을 통해서만 업데이트 된다. 컴포저블의 수명 주기 컴포지션 시작 리컴포지션 컴포지션 종료 리컴포지션은 일반적으로 State<T> 객체가 변경되면 트리거됩니다. 컴포지션 내 컴포저블의 분석 컴포지션 내 컴포저블의 인스턴스는 호출 사이트(call site)로 식별된다. (호출 사이트는 컴포저블이 호출되는 소스코드 위치...

Dec 22, 20236 min read
[Android] Compose 수명 주기, 부수효과

[Android] rememberUpdatedState 완벽 이해

rememberUpdatedState 정의 공식 문서에는 다음과 같이 적혀있다. 값이 변경되는 경우 다시 시작되지 않아야 하는 효과(Effect)에서 값 참조 포스팅을 정리하면서 정의한 rememberUpdateState는 아래와 같다. remember는 초기 컴포지션에서만 값을 저장하고 리컴포지션 때 들어온 값은 저장하지 않는다. 리컴포지션 때 들어온 값도 저장하고 싶을 때 rememberUpdateState를 사용한다. 이게 도대체 ...

Dec 14, 20234 min read
[Android] rememberUpdatedState 완벽 이해

Jinukeu

33 posts