Home Java 멀티스레딩, 병행성, 성능 최적화 강의 후기
Post
Cancel

Java 멀티스레딩, 병행성, 성능 최적화 강의 후기


본 포스팅은 글또 9기 활등 중 Udemy 로부터 강의 쿠폰을 지원받아 작성되었습니다.


【한글자막】 Java 멀티스레딩, 병행성 및 성능 최적화 【한글자막】 Java 멀티스레딩, 병행성 및 성능 최적화

이번 포스팅은 ‘글또 9기’ 활동 중 일부로, Udemy에서 지원해주신 쿠폰으로 수강한 【한글자막】 Java 멀티스레딩, 병행성 및 성능 최적화 강의에 대한 후기 글 입니다. 멀티스레드의 필수(기초)이론부터 심화주제까지 폭넓게 다루고 있고, 멀티스레딩과 병행성에 대한 이론적인 학습은 물론 관련 코드를 포함한 실습과정이 잘 구성되어 있습니다. 요즘 개인적인 사정(결혼준비, 회사업무 등등…)으로 준비해야 할 것이 너무 많아 글쓰기에 충실하지 못했는데, 다시 마음을 다잡고 초심으로 돌아가야겠습니다.

들어가며

데이터 엔지니어링에 관심을 가질수록, 그 기반이 되는 백엔드 엔지니어링에도 관심이 생기게 됩니다. 회사 업무인 마이데이터와 관련된 시스템 아키텍처에도 백엔드: 그 중에서 멀티스레딩을 통한 병행성은 성능최적화에 핵심이 됩니다. 사실 멀티스레딩은 취준생 시절 떄 이론적인 공부만 얕게 해봤지 제대로된 강의를 통해 학습해 본 적은 없어 이번 기회로 멀티스레드 아키텍처의 기초부터 성능 최적화, ReentrantLock, Lock-Free 알고리즘, 비동기-논블록킹IO가상스레드 등을 공부했는데 듣길 너무 잘했다는 생각이 들었습니다. 추천드리는 이유는 다음과 같습니다.

  1. 강사님(Michael Pogrebinsky) 설명이 굉장히 깔끔합니다.
    • Thread, Runnable과 같은 정말 기본 내용으로 시작하여 심화된 개념까지 깔끔하게 정리하여 전달해줍니다.
    • 불필요한 내용으로 혼란을 주지 않고 핵심만 짚어줍니다. 말씀하시는 흐름이 수강생이 이해하기 편하도록 배려하여 짜셨다는 것이 느껴졌습니다.
  2. 강의 구성이 개념을 익히기에 적합합니다.
    • 이론을 코드로 옮겨 실습하는 과정과, 섹션 별 코딩실습 부분은 배우는 중간에 점검하고 넘어가기 좋은 구성입니다.
    • 처음에 개념을 전체적으로 정리하고 설명한 개념 그대로가 옮겨진 코드 실습, 그리고 적절한 예제(코딩연습)로 개념을 재점검합니다. 특히 관련 개념을 완벽하게 짚고 넘어갈 수 있는 실무 내용을 반영한 예시를 들어 설명해줍니다.
  3. 실무와 밀접하게 연관된 내용을 배웁니다.
    • 업무 자체에 코드 그대로 적용가능하진 않지만, 다루는 개념들이 실무에 직접적으로 연관되어 있습니다. 업무와 연관성이 있으나 의심스러웠던 부분들이 강의를 듣고 나서 훨씬 깔끔하게 정리되었습니다.

배우는 내용

강의에서 배우게 되는 내용은 다음과 같습니다.

  1. 운영 체제의 기본 내용 및 멀티스레딩과 병행성이 필요한 이유
  2. 멀티스레딩의 기본 - Java에서 스레드를 생성하는 방법 및 스레드 간에 소통하는 방법
  3. 멀티스레드 병렬 실행 애플리케이션의 성능 관련 고려 사항 및 설계 패턴. 지연 시간 또는 처리량을 최적화하는 방법
  4. Java에서 스레드 간에 데이터를 공유하는 방법. 발생할 수 있는 모든 함정과 어려움 및 솔루션과 모범 사례
  5. 반응성과 성능을 향상시킬 수 있는 락이 걸리지 않은 고급 알고리즘 및 데이터 구조

강의 목차로 정리하면 다음과 같습니다.

  1. 개요
  2. 스레딩 기초 - 스레드 생성
  3. 스레딩 기초 - 스레드 조정
  4. 성능 최적화
  5. 스레드 간 데이터 공유
  6. 병행성 문제와 솔루션
  7. 락킹 심화
  8. 스레드 간 통신
  9. Lock-Free 알고리즘, 데이터 구조 및 기술
  10. 고성능 IO를 위한 스레딩 모델
  11. 가상 스레드와 고성능 IO
  12. 마무리

사전 점검

강의 처음은 개요를 통해 멀티스레딩의 기본적인 이론을 먼저 다루고 시작합니다. 아래 내용은 바로 코드 실습부터 들어가고 싶으신 분들을 위해 빠르게 훑어볼 수 있도록 첫 개요 섹션을 정리한 내용입니다. 학부 때 외웠던 기억이 솔솔 나더라구요 :)

멀티스레드가 필요한 이유

  1. responsiveness(응답성)
    • 개별 task들을 각각의 thread 가 처리함으로서 응답성을 향상시킬 수 있다.
    • 이런 multitasking은 Concurrency라고 한다. 그리고 이런 multitasking은 한개의 코어로도 구현할 수 있다.
  2. performance(성능)
    • 단일 thread 로 구현하는 것 보다 훨씬 빠르게 정해진 기간동안 일을 해결할 수 있다.
    • 마찬가지 동일한 이유로 하드웨어 수 나 서비스를 유지하는 공수가 줄어든다.

프로세스,스레드 동작 방식

  1. 컴퓨터 전원을 켜면 운영체제가 disk에서 메모리로 로드된다. (이때 다른 프로그램들은 파일 형태로 디스크에 있다.)
  2. 사용자가 프로그램을 실행시키면 해당 프로그램을 디스크에서 가져와, 인스턴스 형태로 메모리에 생성한다. (이때의 인스턴스를 ‘프로세스(Process)’ 혹은 ‘어플리케이션 컨텍스트(Context of an Application)’ 라고 한다.) (따라서 각각의 프로세스는 완전히 구분되어 있다.)
    • 프로세스의 메타데이터는 다음과 같다.
      • PID : 어플리케이션이 읽고 쓰기 위해 여는 파일
      • Code : CPU에서 실행되는 프로그램 명령어
      • Data(Heap) : 어플리케이션 실행에 필요한 모든 데이터가 들어있음
      • Main Thread : 적어도 하나의 메인 스레드가 있음 (멀티 스레드 환경에서는 이 Stack, Instruction Pointer 덩어리가 여러개 생성되는 것이고 나머지는 공유한다.)
        • Stack : 지역변수가 생성되고 함수가 실행되는 영역
        • Instruction Pointer : 스레드가 수행할 다음 영역을 가르키는 포인터.

컨텍스트 스위치(Context Switch)

  1. 컨텍스트 스위치의 정의
    • 일반적으로 프로세스는 다른 프로세스들과 독립적으로 움직인다.
    • 코어 수 보다 프로세스가 더 많고, 각 프로세스는 스레드 하나를 기본으로 가진다.
    • 스레드 하나를 수행하고, 멈추고 스케줄링에 따라 다른 스레드를 수행하는 것을 Context Switch라 한다.
  2. 컨텍스트 스위치의 주의점
    • 동시에 많은 스레드를 다룰 때는 효율이 떨어질 수 밖에 없다. 이는 병행성의 대가이다.
      • CPU에서 실행되는 각 스레드는 CPU내 레지스터, 캐쉬, 메모리의 커널 리소스를 사용하게 되는데, Context Switch 단계에서 이를 전부 저장해두고, 다른 스레드의 데이터를 CPU와 메모리에 복원해야 하기 때문이다.
    • 너무 많은 스레드를 다루게 되면 Thrashing 이 발생하게 된다. Thrashing은 운영체제가 우리가 하고 싶은 일에 시간을 할애하기보다, Context Switch 작업에 더 많은 시간을 할애하게 되는 것이다.
    • 한 프로세스 내의 스레드는 자원을 공유하기 때문에, 동일한 프로세스 내의 컨텍스트 스위치가 다른 프로세스 내 스레드 간의 컨텍스트 스위치보다 효율적이다.

운영체제의 스레드 스케줄링 방법

  1. First Come, First Serve : 먼저 도착한 스레드를 먼저 실행하는 방법
    • 다른 thread의 기아 문제를 야기한다.
  2. Shortest Job First : 실행시간이 짧은 스레드를 먼저 실행한다.
    • 실행시간이 긴 스레드는 영영 실행이 안될 수 있다.
  3. (실제) Epochs
    • 운영체제는 Epoch에 맞추어 시간을 적당한 크기로 나눈다. 그리고 각 스레드의 타임스레드를 종류별로 에폭에 할당한다. 하지만 모든 스레드가 각 에폭에서 완료되는 것은 아니다.
  4. (실제) Dynamic Priority
    • Dynamic-priority = Static-priority(개발자가 미리 정해둔 우선순위) + bonus(각 Epoch 마다 OS가 세팅한다 ex) 실시간 스레드 등에 더 점수를 부여함, 기아현상 역시 고려함)

Thread를 사용하는 경우, Process를 사용하는 경우

  1. Thread를 사용하는 multi-thread architecture
    • 자원을 많이 공유하는 경우 멀티스레드 아키텍처가 유리할 것이다.
    • Thread가 생성과 파괴에 훨씬 빠르며, 같은 `프로세스 내의 컨텍스트 스위치는 프로세스 간의 스위치보다 빠르다.
  2. Process를 사용하는 multi-process architecture
    • 보안성과 안정성이 중요하다면 독립된 프로세스로 수행하는 것이 나을 수 있다.(멀티스레드 앱은 스레드 하나가 앱 전체를 다운시킬 수 있음)
    • 서로 관련없는 작업을 하나의 프로세스로 통합하는 것 역시 의미가 없다.

소감

Udemy에는 참 좋은 강의들이 많이 있는 것 같습니다. 이번 강의도 꼼꼼하게 정리하여 멀티스레딩 관련된 포스팅을 연재하고자 합니다. 위 강의는 JVM, 멀티스레딩, 성능 최적화에 관심은 많으나 시간이 부족한 분들, 이론/실무를 병행하여 빠르게 학습하시고 싶은 분들께 추천드립니다.

참고문헌

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