본문 바로가기
파이썬

파이썬 concurrent 프로그래밍

by 혜룐 2015. 11. 10.


파이썬에서 concurrent프로그래밍에대한 내용을 정리한다.
(파이썬 인 프랙티스를 읽고..)


* 동시성은 여러방식으로 구현할수있다.
구현방식의 가장 큰 차이는 공유메모리를 활용하는경우로, IPC(Inter process communication )를 통해 간접적으로 메모리에 접근, lock을 통해 직접 접근하는 방법이 있다.


멀티쓰레드는 보통 동기화를 통해
강제할수있는데,멀티쓰레드개발시 atomic이슈가 있다.
두 개의 프로세스가 동시에 참조하는 변수를 업데이트하는 동작을 수행하기 위해서는 이 과정이 ‘atomic’하게 처리되어야 하는것을 말한다.


> atomic? 한쪽에서는 A라는 값을 B라는 값으로 변경했는데, 다른 쪽에서는 그 때 새로 업데이트된 B라는값이 아닌 A라는 값으로 읽어가게 되는 문제가 생길 수 있다. 혹은 A값을 읽어야 하는데 읽는 중간에 B값으로 변경되어 문제가 발생할 수도 있을 것이다. 이런 경우에는 해당 값을 atomic하게 보장해야 한다. 공유메모리에서 변경이 일어나는 그 값 자체를 lock해 원자성을 보장하는것이다. ( java에서는 volatile 또는 atomic패키지에 자료구조를 사용. http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html)


멀티프로세싱은 별개의 프로세스를 서로 독립적으로 실행하는 경우를 의미한다. (일반적으로 IPC를 활용해 공유데이터에 접근)
동시실행대신 concurrent wating을 기반으로 한것이다.(비동기 IO를 구현할때 활용 https://docs.python.org/3/library/concurrent.futures.html" target="_blank">https://docs.python.org/3/library/concurrent.futures.html )
파이썬은 GIL때문에 한 프로세서 코어에서만 실행이 가능하다. 그래서 멀티프로세싱을 이용하면 (같은 프로세스에서 여러 스레드를 사용)멀티쓰레드로 처리하는것 보다 더 큰 성능향상을 볼 수 있다. (아래 다루게될 IO위주동시성의 경우)


그래서..
* 파이썬은 명시적으로 락을 사용하는경우 threading.Semaphore threding.Lock multiprocessing.Lock등의 클래스를 통해 지원한다.
또는 락을 명시적으로 활용하지 않는 경우 concurrent.futures모듈(3.2버전부터) queue.Queue multiprocessing큐 컬렉션( multiprocessing.JoinableQueue) 클래스를 통해 이를 지원한다.
또는 multiprocessing.Value를 활용하거나, 여러개면 multiprocessing.Array를 통해 만든다.
(즉. 동시 접근을 보장하는 자료구조를 사용하는것이다.)


# CPU위주의 동시성
책에서 다루고 있는 예제로 이미지를 리사이징하는것이 나온다. 목표는 멀티코어를 활용하고 싶고, 이미지를 한꺼번에 리사이징하는데 있다.
결론과 중요포인트만 정리하면..
멀티프로세스풀>멀티프로세스(큐)>싱글프로세스>멀티스레드 순으로 수행되었다.
1.
이미지크기 변환이 cpu위주의 연산이라 멀티프로세스가 가장 좋은 결과를 얻은것이다. ( 멀티프로세스의 수행속도는 코어개수에 비례한 속도향상수치를 확인할수 있다 = 멀티프로세스가 작업량을 각 코어에 분산시켜 처리 )
2.
큐와 멀티프로세스
multiprocessing.JoinableQueue 는 수행할잡.
(thread safe한 큐를 의미하며, multiprocessing.Queue 클래스가 아니다.)
multiprocessing.Queue는 결과를.
3.
future와 멀티프로세스
3.2부터 concurrent.futures모듈이 도입되었다.
( concurrent.futures.ProcessPoolExecutor / concurrent.futures.ThreadPoolExecutor )
( 자세한 코드와 내용은 문서로 대체한다.
https://docs.python.org/3/library/concurrent.futures.html" target="_blank">https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor
https://docs.python.org/3/library/concurrent.futures.html" target="_blank">https://docs.python.org/3/library/concurrent.futures.html )


#IO위주의 동시성
다루는 예제는 rss피드를 다운로드 하는 예제로 200개의 rss를 다운로드 하는 방식을 예로 든다.
결론은 이작업은 싱글프로세스보다 멀티작업이 더 좋은 성능결과를 볼수있다는 것이다.
1.
큐와 쓰레드활용
thread safe한 큐로 작업큐와 결과를 담는 큐. 그리고 작업은 쓰레드로 하되 스레드개수는 코어숫자의 배수로 (4배) 지정했다.
add_jobs()>queue.Queue.get () 작업큐>코어x4 threading.Thread>task.done ()&queue.Queue.put () 결과큐>process ()
2. future와 쓰레드
이 예제는 concurrent.futures.ThreadPoolExecutor 로 사용하는 예를 다뤘으며, 자세한 코드와 내용은 문서로 대체한다.
https://docs.python.org/3/library/concurrent.futures.html" target="_blank">https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor




데뷰2014발표자료에는 더 자세한 얘기가.. ㅎㅎ 

http://deview.kr/2014/session?seq=47