Block, NonBlock / 동기, 비동기

DD·2021년 1월 25일
1

프로그래밍 이론

목록 보기
9/12
post-thumbnail

Block / NonBlock

  1. 호출되는 함수가 바로 리턴하는가(NonBlock),
    하지 않는가(Block)?
  1. 어플리케이션 실행 시 운영체제의 대기큐에 들어가는가(Block),
    들어가지 않는가(NonBlock)?
  1. 요청에 대한 system call이 완료된 후에 응답을 보내는가(Block),
    실행 여부와 관계없이 바로 보내는가(NonBlock)?

Block

어플리케이션 실행 시 운영체제 대기큐에 들어가면서
요청에 대한 system call이 완료된 후에 응답을 보낸다.

1) A가 B를 호출했을 때

2) B가 자신의 작업을 모두 마칠 때까지 A에게 제어권을 넘겨주지 않고

3) A를 대기하게 만든다.

NonBlock

애플리케이션 실행 시 운영체제 대기 큐에 들어가지 않고,
실행 여부와 관계없이 바로 응답을 보낸다.
바로 응답하기 힘든 경우, 에러를 반환하는데 정상데이터를 받을 때까지 계속해서 요청을 다시 보낸다.

1) A가 B를 호출했을 때

2) B가 바로 return하면서 A에게 제어권을 넘겨주고

3) A가 다른 일을 할 수 있는 기회를 준다.


동기(Synchronous) / 비동기(Asynchronous)

IO이벤트 통지 모델.
NonBlock에서 제기된 문제를 해결하기 위해 고안됨.

호출되는 함수의 작업 완료를 호출한 함수가 신경쓰는가(Synchronous),
신경쓰지 않는가(Asynchronous)

시스템콜을 기다리는가(Synchronous),
기다리지 않는가(Asynchronous)

notify를 사용자 프로세스가 담당하는가(Synchronous),
커널이 담당하는가(Asynchronous)

A : B를 호출하는 함수
B : A가 호출한 함수

function A(){
	B(callback)
}

동기(Synchronous)

시스템콜을 기다리며(notify를 사용자 프로세스가 담당)
시스템의 반환을 기다리는 동안 대기큐에 머루는 것이 필수가 아니다.

1) A가 B를 호출하고

2-1) A가 호출된 B의 return을 기다리거나

2-2) B의 return을 바로 받더라도
B의 작업이 완료되었는지 여부를 A가 스스로 계속 확인하면서 신경쓴다.

비동기(Asynchronous)

시스템콜을 기다리지 않으며(notify를 커널이 담당)
요청에 대해 처리완료 여부에 관련없이 응답하고 다음코드를 실행한다.
이후에 운영체제에서 처리완료여부를 알려주고 응답한다.

1) 함수A가 함수B를 호출하면서 callback을 전달하고

2) 함수B의 작업이 완료되면 B가 A에게 전달받은 callback을 실행하고

3) A는 해당 작업의 완료 여부를 신경쓰지 않는다.




조합

익숙한 조합

Block - Synchronous

호출되는 함수(B)가 작업이 완료 될 때까지 제어권을 갖고 있으며(Block)
호출하는 함수(A) B의 작업이 완료되었는지 계속 확인한다.(Synchronous)

  • file.read()
  • file.write()
  • psmt.executeUpdate() 등..

  • 프로그램이 블로킹을 일으키는 시스템 함수를 호출
  • 한 작업당 한 번의 사용자-커널사이의 문맥교환 발생
  • 정지된 프로그램은 CPU를 사용하지 않고 커널의 응답을 대기
  • 프로그램 관점에서 보면 마치 처리로직이 오래걸리는 것 같지만, 사실은 커널의 일을 기다리느라 블록되어 있는 것이다. 이게 개선 포인트

NonBlock - Asynchronous

호출되는 함수(B)가 바로 Return 하면서 제어권을 넘긴다(NonBlock)
호출하는 함수(A)는 B의 작업 완료 여부를 상관하지 않는다.(Asynchronous)

  • asyncFileChannel.read(..., completionHandler)
  • asyncFileChannel.write(..., completionHandler)
  • Node.js
  • Vert.x

이 두 조합은 우리가 잘 알고 있는 형태로 동기/비동기와 Block/NonBlock을 같은 것이라 생각하게 만들 수 있다.

하지만 위에서 설명한대로, 이 두가지는 비슷하지만 다르다.

  • 시스템콜이 즉시 IO개시 여부를 반환한다. 사용자프로세스는 다른일을 할 수 있고(CPU는 다른 업무를 볼 수 있다), IO는 백그라운드에서 처리된다.
  • IO 응답이 도착하면 신호나 콜백으로 IO전달을 완료한다.


낯선 조합

NonBlock - Synchronous

호출되는 함수(B)가 바로 Return하면서 제어권을 넘긴다(NonBlock)
호출하는 함수(A) B의 작업이 완료되었는지 계속 확인한다.(Synchronous)

호출하는 함수(A)가 B의 작업을 계속 확인하는 것은, return 값을 기다리거나, 물어보거나 두 가지가 있다.

NonBlock이라 return 값을 기다릴 일은 없고, 물어보는 일이 남는다.

즉, B를 호출해서 바로 리턴값과 제어권을 받아 다른 작업을 할 수 있게 되지만, B의 작업이 완료 된 것은 아니며, A가 B의 작업 완료 여부를 계속 묻는 것이다.

  • 동기블로킹의 개선안이지만 비효율적이다.
    왜냐하면 위에서 정리했듯이 논블로킹방식은 정상데이터가 올 때 까지 계속 시스템콜을 하며 문맥교환을 한다.
  • IO 지연(latency) 초래한다.

Block - Asynchronous

호출되는 함수(B)가 작업이 완료 될 때까지 제어권을 갖고 있으며(Block)
호출하는 함수(A)는 B의 작업 완료 여부를 상관하지 않는다.(Asynchronous)

이 경우에는 A가 B의 작업 완료 여부를 신경쓰지 않아도(Asynchronous) 어차피 B가 작업이 완료 될 때까지 return을 하지 않고 제어권도 넘겨주지 않기 때문에 Block - Synchronous와 차이가 나지 않는 것 같다.

Block-Asynchronous 방식은 이점이 없어서 일부러 사용할 필요가 없긴 하지만, 의도치 않게 이 방식으로 동작하는 경우가 있다고 한다.

NonBlock-Asynchronous 방식으로 동작 중에 그 과정 중에 하나라도 Blocking으로 동작한다면, 의도치 않게 Block-Asynchronous 방식으로 동작할 수 있다는 것이다.

대표적인 예시로 Node.js - MySQL 조합이 있다.

MySQL에서 제공하는 드라이버가 Blocking 방식이기 때문에,
Node.js에서 Async로 접근해와도 결국 DB 작업 호출시에 해당 MySQL 드라이버를 호출하기 때문이라고 한다.

  • IO는 논블로킹이고 알림(notify)가 블로킹인 방식이다.
  • select() 시스템함수 호출이 사용자프로세스를 블로킹한다.
  • 비효율적이다.


정리

  • Block/NonBlock
    호출되는 함수가 바로 리턴하는가(NonBlock), 하지 않는가(Block)의 차이

  • Synchronous/Asynchronous
    호출하는 함수가 호출되는 함수의 작업 완료 여부를 신경쓰는가(Sync), 쓰지 않는가(Async)의 차이

  • 성능과 자원의 효율적 사용 관점에서 가장 유리한 모델은 Async-NonBlock 모델이다.

기타 의견

  • Nonblocking과 Async를 관심사 관점이 아니라 다음과 같이 동작 관점에서도 구분할 수 있다
    • NonBlocking은 제어문 수준에서 지체없이 반환하는 것
    • Asynchronous는 별도의 쓰레드로 빼서 실행하고, 완료되면 호출하는 측에 알려주는 것
  • 입장(?)을 통한 구분
    • Blocking/NonBlocking은 호출한 입장에서의 특징
    • Sync/Async는 처리되는 방식의 특징

출처

Blocking-NonBlocking-Synchronous-Asynchronous

IO모델 (동기vs비동기vs블로킹vs논블로킹)

profile
기억보단 기록을 / TIL 전용 => https://velog.io/@jjuny546

0개의 댓글