동시성 처리 모델 - 스레드 잠금장치, 함수형 프로그래밍

bp.chys·2021년 6월 2일
0

TIL(Today I Learned)

목록 보기
2/11

개념 정의

동시성과 병렬성

동시성 프로그램은 여러 사건을 한꺼번에 처리 해야하는 문제 관점으로 볼 수 있고,
병렬성은 프로그램 내 각기 다른 부분을 병렬로 실행함으로써 처리 속도를 높이는 해법적인 관점으로 볼 수 있다.

동시성과 병렬성이 혼동되는 이유는, 전통적으로 사용하는 스레드와 잠금장치 방식에서는 병렬성을 직접 지원하지 않기 때문이다. 이 방법으로 멀티코어를 활용하는 방법은 동시적인 프로그램을 작성하여 병렬로 동작하는 하드웨어에서 실행하는 것이다.

동시적 프로그래밍

  • 동시성이란 단순히 병렬성을 활용하는 것 이상을 의미한다.
  • 동시성은 반응형 시스템의 핵심이다.
  • 정확하게 구현된 동시성은 소프트웨어에 대해 반응성이 높고, 장애를 허용하며, 효율적이고 간단하게 만들어준다.

1. 스레드와 잠금장치

상호배제와 메모리 모델

  • 스레드는 공유메모리를 사용해서 다른 스레드와 소통한다.
  • 동기화처리를 통해 하나의 메서드는 하나의 스레드에서만 접근 가능하도록 제한할 수 있다.
    • 동기화 처리는 뮤텍스, 모니터, 임계영역 등 내재된 잠금장치를 사용한다.
  • 그러나 모든 메서드가 동기화되면 대부분의 스레드는 블락된 상태로 시간을 보내게 될 것이다.
  • 이보다도 심각한 문제는 하나의 스레드가 두 개 이상의 잠금장치를 획득하여 데드락 상태가 될 수 있다는 점이다.
  • 잠금 장치를 가진 채로 외부 메서드를 호출하게되면 데드락의 위험성을 초래한다.
  • 잠금장치는 최대한 짧게 보유해야 한다.

내재된 잠금장치를 넘어서

  • 자바에서 내재된 잠금장치는 syncronized 블록이다.
    • 데드락에 빠지면 스레드를 원상복귀 시킬 방법이 없다.
    • 강제로 중단시키는 타임아웃 기능이 없다.
  • ReentrantLock을 사용하여 해결
    • lockInterruptibly()를 통해 데드락 상태에 빠진 스레드를 가로챌 수 있다.
    • 잠금장치를 기다리는 상태에서 타임아웃 제한을 걸 수 있다.
  • 원자변수 (java.util.concurrent.atomic)
    • 필요한 경우에 잠금장치를 획득하는 것을 잊지 않는다.
    • 잠금장치가 하나도 개입되지 않기 때문에, 원자 변수에 대한 데드락이 불가능하다.
    • 잠금장치나 블로킹에 기대지 않고 동기화를 구현하는 논블로킹, 락프리 알고리즘의 기초를 제공한다.

Concurrent 패키지

  • 스레드를 생성할 때, 무작정 생성하면 서버가 다운될 수 있으므로 스레드 풀을 사용해서 재사용하는 것이 효율적이다.
    • 스레드 풀의 크기는 계산을 집중적으로 한다면 코어 수와 동일한 수의 스레드를 풀에 담고, IO 중심인 경우 코어보다 많은 수를 사용하는 편이 좋다.
  • 생산자/소비자 패턴을 이용해서 병렬 처리를 기대해 볼 수 있다.
  • 이때 concurrent 패키지의 블로킹 큐를 사용해서 작업을 전달한다.
    • 블로킹 큐를 사용하는 이유는 생산자와 소비자의 작업 속도를 얼추 맞추어 큐가 메모리 용량을 넘지 않게 만들기 위해서이다.
  • 보통 소비자의 속도가 더 느리게 되는데 여러개의 소비자를 만들어서 더 많은 병렬처리를 이뤄내면 전체 속도를 크게 향상시킬 수 있다.
  • 이때 결과를 저장하는 Map이 동시성을 지원하지 않으면 소비자를 늘릴 때 스레드 경합때문에 오히려 시간이 더 걸릴 수 있다. 따라서 동시성을 지원하는 concurrentHashMap을 사용해야 한다.

2. 함수형 프로그래밍

불변 상태

  • 동시성 문제는 여러 개의 스레드에 의해서 공유되고 값이 변경되는 데이터에 한해서 적용된다.
  • 즉, 불변 데이터는 잠금장치 필요없이 여러 스레드가 안전하게 접근할 수 있다.
  • 어플리케이션 내에 모든 가변상태를 제거하는 것이 중요하다.

함수 동시성

  • 함수는 계산 순서가 독립적이다. (결정적 순서)
    • 함수는 참조 투명성을 갖는다. 이는 프로그램 전체 동작을 변경하지 않으면서 함수가 실행되는 순서를 안전하게 바꿀수 있또록 한다.
  • 함수형 언어는 선언적인 느낌이 강해서 연산 과정이나 순서보다는 결과에 집중한다.
  • 이렇게 계산 순서를 바꿀 수 있기 때문에 함수 코드의 병렬화가 쉽다.
  • 각각의 계산은 future를 가지고 다른 스레드에서 수행된다.

자바 스트림

  • 스트림의 집계 연산은 함수스타일의 코딩을 지원하여 병렬적으로 연산을 처리할 수 있다.

참고자료

7가지 동시성 모델 by 폴 부처

profile
하루에 한걸음씩, 꾸준히

0개의 댓글