콘텐츠로 건너뛰기
Home » synchronization

synchronization

asyncio의 동기화수단들

asyncio는 단일 스레드에서 비동기 코루틴을 사용하여 동시성 처리를 한다. 따라서 asyncio의 세계에서는 적어도 멀티 스레드에서 발생할 수 있는 자원 선점문제가 없을 것이라 생각할 수 있다. 전적으로 틀린 것은 아니다. 스레드가 1개밖에 없기 때문에 메모리 내의 특정한 객체를 동시에 액세스하는 일은 없을 것이다. 그러나 그외의 IO와 관련된 자원은 여전히 선점 문제가 발생할 수 있다. 이러한 문제를 피하기 위해서 asyncio는 threading과 유사한 동기화 수단들을 제공하고 있으며, 이들의 사용 방법 또한 거의 유사하다. asyncio에서 제공하는 동기화 수단에는 다음과 같은 것들이 있다.

  • 락(Lock)
  • 이벤트(Event)
  • 컨디션(Condition)
  • 세마포어(Semaphore)
  • 바운디드세마포어(BoundedSemaphore)
더 보기 »asyncio의 동기화수단들

컨디션을 통한 스레드 동기화 예제

동시성을 다룰 때 여러 스레드가 하나의 자원에 순차적으로 접근하게 하거나, 반대로 특정한 시점에 동시에 작동하도록 하는 등의 상황에 제대로 대응할 수 있도록 락이나 이벤트와 같은 동기화 수단을 사용한다. 컨디션은 컨디션 락이라고도 하는데, 간단히 말하자면 이벤트와 락을 적절히 결합한 것이다. 락이나 R락을 사용하는 경우, 락을 획득한 구간의 코드는 항상 하나의 스레드만 진행할 수 있다. 락을 사용하는 중간에 다른 스레드로 사용 권한을 넘기려 한다면 현재 획득한 락을 해제하여 크리티컬 구간을 끝내야 한다. 그런데, 경우에 따라서는 atomic한 자원을 사용하려는 구간에서 해당 자원이 준비되지 않아 구간 내에서 일시적으로 실행을 중단하고 대기해야 하는 상황이 될 수 있다. 이런 경우에 컨디션 락을 사용한다.

컨디션은 락을 획득한 구간내에서 락을 일시적으로 반환하고 기다리는 역할을 가능하게 한다. 컨디션 락을 기다리는 스레드는 락을 해제하면서 블럭된다. 그러면 같은 컨디션락을 획득하려는 다른 스레드에게 제어권이 넘어가는데, 이러한 스레드 중에 해당 자원을 생성하는 역할을 담당하는 스레드가 있다면 이 생산자 스레드는 자원을 생성한 후, 이벤트와 비슷하게 대기 중인 다른 스레드를 깨워주게 된다. 생산자 스레드가 락을 반환하고 나면 중단됐다가 깨어난 스레드는 락을 다시 획득해서 해당 자원을 독점적으로 사용할 수 있게 된다.

중요한 것은 컨디션락은 락의 한 종류이기 때문에 대기중인 상태에서 깨어난 스레드는 그 즉시 실행을 재개하는 것이 아니라, 해당 락을 선점한 다른 스레드가 (이 스레드가 자신을 깨워주었을 것이다.) 락을 반환한 후 다시 그 락 객체를 획득해야 실행을 재개할 수 있게 된다는 것이다.

더 보기 »컨디션을 통한 스레드 동기화 예제

concurrent.futures를 이용한 병렬처리 방법

리스트와 같은 일련의 데이터를 하나의 함수로 반복 처리해야 할 때, 이를 여러 프로세스에서 분산하여 동시에 처리하게 하면 전체적인 작업 시간을 단축시킬 수 있다. 서브 프로세스를 사용하는 방법으로는 multiprocessing.Process 를 사용하는 방법이 있지만, 프로세스별로 분산하여 처리한 데이터를 다시 수집하여 취합하는 과정이 좀 번거롭다. 또한 데이터 매우 많을 때 너무 많은 프로세스가 생기지 않도록 프로세스 풀을 관리하는 로직을 직접 구현해야하는 점이 번거롭기도 하다. concurrent.futures는 이러한 분산처리에 특화된 작업을 쉽게 구현할 수 있도록 도와주는 라이브러리로 사용방법이 쉽고, asyncio와 비슷한 Future라는 개념을 사용하고 있다.… 더 보기 »concurrent.futures를 이용한 병렬처리 방법