Post

부록 A - 동시성 II

프로세스 작업

  • I/O Bound : 소켓 사용, 데이터베이스 연결, 가상 메모리 스와핑 등
  • CPU Bound : 수치 계산, 정규 표현식 처리, 가비지 컬렉션 등

프로그램 성격

  • 프로그램이 주로 프로세서 연산에 시간을 보낸다면,
    • 새로운 하드웨어를 추가해 성능을 높여야 한다.
    • 스레드를 늘린다고 빨라지지 않는다.(CPU 사이클은 한계가 있기 때문이다.)
  • 프로그램이 주로 I/O 연산에 시간을 보낸다면,
    • 동시성(concurrent)이 성능을 높여줄 수 있다.
    • 따라서 쓰레드를 추가하여 성능 향상을 이룰 수 있다.

다중 쓰레드 프로그램

  • 다중 쓰레드 프로그램을 깨끗하게 유지하려면 잘 통제된 곳으로 쓰레드 관리를 모아야 한다.
  • 쓰레드를 관리하는 코드는 쓰레드만 관리해야 한다.(SRP)
  • 동시성은 그 자체가 복잡한 문제이므로 SRP가 특히 더 중요하다.

Race Condition

  • 바이트 코드 \(N\)개를 쓰레드 \(T\)개로 실행할 때 발생 가능한 순열 수는 \(\frac {(NT)!} {N!^T}\)
  • 자바 코드 return ++id는 바이트 코드 8개에 해당된다.(id는 int)
    • 쓰레드 2개가 동시 실행한다면 발생 가능한 순열은 12,870개
    • long 타입이라면 발생 가능한 순열은 2,704,156개
  • 따라서 임계 구역에서는 원자적 연산(atomic operation)이 중요하다.
    • 공유 객체/값이 있는 곳, 동시 읽기/수정 문제를 일으킬 소지가 있는 코드를 알아야 한다.
  • 자바에서 동기적 실행을 위해 synchronized 키워드, Executor 프레임워크, AtomicInteger 클래스,

데드락

  • 데드락 발생 조건 4가지
    • 상호 배제(Mutual exclusion)
      • 여러 쓰레드가 동시에 사용하지 못하며, 개수가 제한적이다.
      • 데이터베이스 연결, 쓰기용 파일 열기, 레코드 락, 세마포어 등의 자원
    • 잠금 & 대기(Lock & Wait)
      • 일단 쓰레드가 자원을 점유하면 필요한 나머지 자원까지 모두 점유해 작업을 마칠 때까지 이미 점유한 자원을 내놓지 않는다.
    • 선점 불가(No Preemption)
      • 한 쓰레드가 다른 쓰레드로부터 자원을 빼앗지 못한다.
    • 순환 대기(Circular Wait)
      • 각 쓰레드가 상대방이 가진 자원을 대기한다.
  • 데드락 예방(Prevent)
    • 상호 배제 조건 깨기(주로 깨기 어렵다.)
      • 동시에 사용해도 괜찮은 자원을 사용한다.
      • 쓰레드 수 이상으로 자원 수를 늘린다.
    • 잠금 & 대기 조건 깨기
      • 각 자원을 점유하기 전에 점유할 수 있는지 확인한다.
      • 만약 어느 하나라도 점유하지 못한다면 지금까지 점유한 자원을 몽땅 내놓고 처음부터 다시 시작한다.
      • 기아(Starvation), 라이브락(Livelock) 문제가 발생할 수 있다.
    • 선점 불가 조건 깨기
      • 필요한 자원이 잠겼다면 자원을 소유한 쓰레드에게 풀어달라 요청한다.
    • 순환 대기 조건 깨기(가장 흔한 전략)
      • 모든 쓰레드에 공통적으로 자원 획득 순서를 정해둔다.
      • 자원을 할당하는 순서와 사용하는 순서가 다를수도 있다.(필요한 이상으로 오랫동안 점유하게 된다.)
This post is licensed under CC BY 4.0 by the author.