7. Concurrency and Parallelism

Python을 활용한 동시성과 병렬화에 대해 알아보자.

52. Use subprocess to manage child processes.

  • subprocess를 사용해서 자식 프로세스를 작동시키고 그 입력 출력 스트림을 관리하라.
  • 자식 프로세스는 Python 인터프리터에서 병렬로 동작해서 CPU 코어 활용도를 최대화할 수 있다.
  • 간단한 사용으로는 run을, UNIX-스타일 파이프라인처럼 조금 더 고급 활용에는 Popen 클래스를 사용하라.
  • communicate 메소드의 timeout 파라미터를 써서 매달린 자식 프로세스나 데드락 문제를 피하라.

53. Use threads for blocking I/O, avoid for parallelism.

  • Python 스레드는 전역 인터프리터 락(GIL) 때문에 복수의 CPU 코어에서 병렬로 동작이 불가능하다.
  • GIL의 존재에도 불구하고 Python 스레드는 여러 작업을 동시에 하는 것처럼 수행하는 쉬운 방법을 제공하기 때문에 유용하다.
  • Python 스레드를 사용하여 복수의 시스템 호출을 병렬로 진행하라. 이는 연산과 동시에 블로킹 입출력을 수행할 수 있게 해 준다.

54. Use lock to prevent data races in threads.

  • Python에 전역 인터프리터 락이 있더라도, 프로그램 내 스레드간 데이터 레이스를 방지할 책임은 당신에게 있다.
  • 복수의 스레드가 상호 배제 락 없이 동일한 오브젝트를 수정하도록 허용한다면 프로그램 내에서 그 자료 구조가 망가질 것이다.
  • threading 내장 모듈에서 Lock 클래스를 써서 복수의 스레드간 프로그램의 불변 조건을 보장하라.

55. Use queue to coordinate work between threads.

  • 파이프라인은 복수의 Python 스레드에서 동작하는 순차적 작업 – 특히 입출력 바운드 프로그램 – 을 정리하는 좋은 방법이다.
  • 동시성을 가진 파이프라인을 만들 때의 많은 문제에 대해 명심하라. 바쁜 기다림, 작업 스레드에 정지를 알리는 것, 잠재적 메모리 폭발.
  • Queue 클래스는 강건한 파이프라인을 만들기 위한 모든 기능이 있다: 블로킹 연산, 버퍼 크기,결합.

56. Know how to recognize when concurrency is necessary.

  • 프로그램은 그 동작 범위와 복잡도가 증가함에 따라 동시적으로 실행되는 프로그램 부분에 대한 요구가 커질 수 있다.
  • 동시성 조절의 가장 흔한 유형은 팬아웃(동시성을 적용할 새 단위를 생성), 팬인(동시성을 적용받는 단위의 실행 종료에 대한 대기)가 있다.
  • Python은 팬아웃과 팬인을 달성하기 위한 여러 방법이 있다.

57. Avoid creating new thread instances for on-demand fan-out.

  • 스레드는 단점이 많다: 많은 스레드를 필요로 할 경우 동작과 실행에 드는 비용이 비싸다. 각각 무시할 수 없는 메모리를 소모한다. 조정을 위해 Lock 인스턴스같은 특별한 도구를 필요로 한다.
  • 스레드는 그 스레드를 시작시킨 코드나 그 스레드의 종료를 대기하는 코드로 예외를 던지는 내장 방법이 없으므로 디버깅이 어렵다.

58. Understand how using queue for concurrency requires refactoring.

  • 고정된 수의 작업 스레드와 함께 Queue 인스턴스를 쓰는 것은 스레드 사용 중 팬아웃과 팬인의 확장가능성을 높인다.
  • 기존 코드를 Queue를 쓰도록 리팩토링하는 것은 매우 손이 많이 간다. 여러 단계의 파이프라인이 필요한 경우라면 더더욱.
  • Queue를 쓰는 것은 다른 내장 Python 특성이나 모듈을 사용하는 접근법에 비해 프로그램이 지렛대로 삼을 입출력 병렬화의 총 수의 한계를 근본적으로 제한한다.

59. Consider threadpoolexecutor when threads are necessary for concurrency.

  • ThreadPoolExecutor는 제한된 리팩토링과 함께 간단한 입출력 병렬화를 가능케 하며, 팬아웃 동시성이 필요해질 때마다 스레드 가동 시작 비용을 회피할 수 있다.
  • ThreadPoolExecutor가 스레드를 직접적으로 씀으로써 생기는 잠재적 메모리 폭발의 가능성은 제거할지라도, 사전에 max_workers의 수를 정해 줘야 하기 때문에 입출력 병렬화를 제한한다.

60. Achieve highly concurrent I/O with coroutines.

  • async 키워드를 통해 정의되는 함수는 코루틴이다. 호출자는 해당 코루틴의 결과를 await 키워드로 받을 수 있다.
  • 코루틴은 수천 개 이상의 함수를 동시에 실행되는 것처럼 보이게 하는 효율적인 방법을 제공한다.
  • 코루틴은 입출력을 병렬화하고 스레드에서 입출력을 수행할 때 생기는 모든 문제를 극복하기 위해 팬아웃과 팬인을 쓸 수 있다.

61. Know how to port threaded I/O to asyncio.

  • Python은 for 루프, with 명령문, 제네레이터, 컴프리헨션, 라이브러리 헬퍼 함수 등등에 대한 비동기 버전을 제공하며 이는 코루틴에서 대체재로 쓰일 수 있다.
  • 내장 모듈 asyncio는 스레드와 블로킹 입출력을 쓰는 기존 코드를 코루틴과 비동기 입출력을 쓰는 코드로 포팅하는 간단한 방법을 제공한다.

62. Mix threads and coroutines to ease the transition to asyncio.

  • asyncio 이벤트 루프의 대기 가능한 run_in_executor 메소드를 이용해 코루틴으로부터 ThreadPoolExecutor 풀에 있는 동기 함수를 실행할 수 있다. 이를 이용해 asyncio로의 하방식 이동을 할 수 있다.
  • asyncio 이벤트 루프의 run_until_complete 메소드를 이용해 동기 코드에서 코루틴을 끝날 때까지 실행할 수 있다. asyncio.run_coroutine_threadsafe 함수는 같은 기능을 스레드 경계간에 지원한다. 이를 함꼐 활용하면 asyncio로의 상방식 이동을 할 수 있다.

63. Avoid blocking the asyncio event to maximize responsiveness.

  • 코루틴에서 시스템 호출을 하는 것 – 블로킹 입출력이나 스레드 시작을 포함해 – 은 프로그램의 민감성을 감소시키고 지연 시간을 늘린다.
  • asyncio.run에 debug=True 파라미터를 전달해 어떤 코루틴이 이벤트 루프를 빠르게 반응하지 못하게 하는지를 찾아라.

64. Consider concurrent.futures for true parallelism.

  • CPU 병목을 C 확장 모듈로 이동시키는 것은 Python의 코드 활용을 최대화하면서도 성능을 개선하는 효과적인 방법이다. 하지만 이는 비용이 크고 버그를 낼 수도 있다.
  • multiprocessing 모듈은 특정한 유형의 Python 연산을 최소한의 노력으로 병렬화할 수 있게 하는 강력한 도구를 제공한다.
  • multiprocessing의 강력함은 내장 모듈 concurrent.futures와 그것의 간단한 ProcessPoolExecutor 클래스를 통해 얻을 수 있다.
  • multiprocessing 모듈의 복잡한 고급 부분을 활용하는 것은 다른 선택지를 다 쓰기 전까지는 피하라.

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중