Home 12장 병렬성과 비동기성
Post
Cancel

12장 병렬성과 비동기성

경합 조건이란 무엇인가

경합 조건은 2개의 프로그램이 같은 자원에 동시에 접근하고, 자원 사용 순서에 따라 결과가 달라지는 경우를 뜻한다. 예를 들어 은행 계좌에 돈을 입금하는 경우 공유자원은 계좌 잔고다.

공유 자원

메모리는 항상 공유 문제와 연관된다. 공유 대상이 메모리가 아닌 경우에도 메모리가 관련된 경우가 많다.

I/O 장치를 서로 공유하는 경우는 흔하다. 한 예로 프린터기기가 있다. 그리고 FPGA가 새로운 공유 대상 자원으로 떠오르고 있다.

프로세스와 스레드

운영체제는 프로세스를 관리하고, 프로세스는 사용자 공간에서 실행되는 프로그램이다. 멀티 코어 시스템에서는 여러 프로그램이 병렬로 실행될 수 있다. 자원을 공유하는 프로세스들은 어떤 방식으로든 서로 통신을 해야 한다.

때로 프로세스가 여러 가지 일에 신경써야 할 수도 있다. 예를 들면 프린트 서버는 프린터 문서 출력을 처리하는 동시에 다른 프로그램이 자신에게 통신하는 것도 신경을 써야 한다.

1980년대 더 쉽게 컴퓨터끼리 통신이 가능하게 해주는 네트워크 관련 코드가 개발 됐다. 핵심은 프로그램이 여러 곳에서 들어오는 활동이나 동작을 기다리며 대기하가 적절한 핸들러를 호출할 수 있게 된 것이다. 하지만 GUI를 통한 대화식 프로그램으로 인해 상황이 달라졌다. 중간에 사용자의 입력을 기다리느라 핸들러가 중간에 대기해야 하는 경우가 많이 생겼다.

필요한 것은 핸들러를 인터럽트할 수 있게 만드는 것이다. 핸들러가 실행하는 중간에 잠시 실행을 중단하고 상태를 저장하고, 나중에 그 위치로 돌아와 실행을 재개할 수 있다는 뜻이다. 저장할 상태는 스택에 있다. 하지만 프로세스당 스택은 하나만 있다.

스레드는 정적인 데이터와 힙을 공유하지만 자체적으로 스택을 갖는 프로그램의 일부분을 말한다. 한 스레드에서 다른 스레드로 실행이 넘어갈 때는 스레드 스케줄러가 CPU 레지스터를 저장해야 한다. 스레드를 사용하면 한 프로세스 안에서 경합 조건을 만들 수 있기 때문에 흥미롭다. 하지만 스레드를 남용하면 여러가지 나쁜 경험을 야기할 수 있다.

  1. 스레드는 데이터를 공유하여 보안문제가 발생할 수 있다.
  2. 한 탭에서 문제가 발생하면 전체 프로세스가 멈춰버린다.
  3. 어떤 스레드가 작업을 완료하는 데 너무 오랜 시간이 걸리면 다른 모든 스레드가 실행되지 못해서 문제가 생길 수 있다.

코드에서 중요한 부분을 상호 배제 메커니즘을 통해 원자적으로 처리하게 만들어야 한다. 이런 목표를 프로그램이 충돌을 피하기 위해 따르는 어드바이저리 락을 만들어서 달성한다. 어느 쪽이 락을 먼저 얻었다면 다음 프로그램은 락이 해제될 때까지 기다려야 한다.

1) 트랜잭션과 작업 크기

성능을 향상할 가장 좋은 방법은 여러 연산을 한 트랜잭션에 넣는 것이다. 트랜잭션에 들어 있는 모든 연산은 모두 다 성공하거나 모두 다 실패한다.

2) 락 대기

블로킹이라는 말은 시스템이 락을 할당할 수 있을 때까지 락을 요청한 프로그램을 일시중단 시킨다는 뜻이다. 논블로킹이라는 말은 프로그램이 계속 실행되고 나중에 락을 얻었는지 여부를 어떤 방식으로든 통지 받게 된다는 뜻이다.

3) 교착상태

교착상태의 원인

  1. 상호 배제 : 공유 자원을 함께 사용할 수 없어서 어느 한 프로세스가 독점적으로 사용해야만 한다.
  2. 점유 대기 : 프로세스들은 어느 자원을 점유한 상태에서 다른 자원을 요청한다.
  3. 비선점 : 프로세스가 할당받은 자원을 강제로 빼앗을 수 없다.
  4. 순환 대기 : 각 프로세스가 서로 순환적으로 다른 프로세스가 갖고 있는 자원을 요구한다.

4) 단기 락 구현

여러 프로세서가 락게 사용하기 위한 ‘검사 후 설정’ 이라는 명령어를 제공한다. 이 명령어는 어떤 메모리 위치에 들어 있는 값을 1로 설정하고, 원래 그 위치에 들어 있던 값을 돌려준다. 처음 이 메모리에는 0이 들어있어야 한다. 둘 이상의 프로세서가 이 명령어를 사용하게 되면 한 프로세서는 0을 반환하지만 나머지 프로세서는 1을 반환한다. 따라서 이 명령어는 락을 직접 구현해 준다.

다른 방법으로 비교 후 바꾸기가 있다. 이는 명령어를 호출하는 쪽에서 예전 값과 새 값을 모두 제공한다. 예전 값이 메모리 위치에 들어 있는 현재 값과 일치하면 메모리의 값을 새로운 값으로 바꾸고 프로세스는 락을 얻는다.

5) 장기 락 구현

아주 오랫동안 락을 소유하고 싶을 때 장기간 락은 메모리보다 좀 더 영구적인 저장소에 저장돼야 한다. 이런 락은 파일을 사용해 구현되는 경우가 자주 있다.

브라우저 자바스크립트

자바스크립트는 사용자 이벤트에 응답하는 짧은 프로그램을 실행하기 위해 만들어졌기 때문에 자바스크립트 구현은 이벤트 루프 모델을 사용한다. 실행할 작업을 이벤트 큐에 추가하고 큐에서 한 번에 하나씩 꺼내서 실행한다.

자바스크립트가 처음 등장했을 당시 비동기 통신을 언어 설계에 포함하지 않았다. 그러나 문서객체모텔(DOM)의 등장과 XHR(AJAX의 기반)의 등장으로 기존의 페이지 로드 모델에서 벗어나 백그라운드에서 브라우저와 서버가 통신할 수 있게 됐다.

비동기 통신을 하게되면 프로그램이 순서대로 실행되지 않는다.

비동기 함수와 프로미스

자바 스크립트의 프로미스는 비동기 콜백 매커니즘을 언어 고유 기능으로 넣어서 라이브러리가 잘못 비동기 연산을 구현하지 못하게 한다. 프로미스에 비동기 연산을 수행하는 함수를 넘긴다. 이 함수는 두 함수를 인자로 받고 첫 번째 함수는 비동기 연산이 성공적으로 종료하면 호출하는 함수(resolve), 두 번째 함수는 비동기 연산이 실패하면 호출해야하는 함수(reject)이다. 프로미스에 넘기는 함수는 비동기 연산을 수행하고, 수행 성공이나 실패에 따라 resolve, reject를 호출하면 자바스크립트가 이를 이벤트 큐에 넣는다. 그러면 then 메서드를 사용하여 프로미스를 실행한다.

프로미스를 사용하는 이점은 프로미스는 체이닝이 가능해서 someting().then().then()…. 스타일의 코드를 작성할 수 있다.

또 다른 비동기 방법으로 async, await이 있다.

This post is licensed under CC BY 4.0 by the author.

11장 성능 향상을 위한 알고리즘 기법

13장 컴퓨터 보안