JMK no matter what

/quickpost/201001240230

이 커멘트 를 위한 해설:

일단 스레드랑 크리티컬 섹션, 뮤텍스 등을 쓰는 전통적인 스레드 기반 프로그래밍 모델은 이해하고 있을 거라고 생각하고.. 요즘 많이들 하는 게 이벤트 기반으로 멀티스레드 어플리케이션을 작성하는 거야. 간단하게 말하자면 메시지 큐를 유지하고, 이것을 동기화하는 작업 등등을 직접 구현하는 게 아니라 프레임워크에서 이같은 작업을 하도록 하고, 우리는 메시지가 왔을 때 메시지를 처리하고, 결과 메시지를 다른 애들에게 보내고 종료하는 함수들만을 제공하는 거지. 이와 같은 작업들을 언어 차원에서 지원하는 가장 대표적인 예가 Erlang 이고. Scala 도 이것과 비슷한 모델을 쓸 수 있는 라이브러리를 표준 라이브러리에서 제공하고 있지.

Stackless Python 은 이와 같은 모델을 파이썬에서 사용할 수 있도록 만든 실험적인 구현인데 (하는 일이 액터 모델과 완전 같은 건 아니지만) 거기에서 가장 큰 문제는 얘가 스레드를 안 쓴다는 것... 파이썬은 Global Interpreter Lock (구글 요망) 때문에 여러 개의 스레드를 돌린다고 해서 속도가 올라가는게 아니거든. 그래서 얘는 싱글 스레드 위에서 여러 개의 가상 스레드 (tasklet) 를 사용해 컨텍스트 스위칭에 들어가는 부하를 줄이는 데 더 중점을 두고 있지. 문제는 근데 알고스팟 저지에서는 많은 작업들이 블러킹 I/O 로 처리되기 때문에 (외부 프로그램 실행/컴파일/네트워크 접근 등이 가장 많은 시간이 드는 작업) 만약 얘들이 블러킹되어버리면 다른 애들까지 실행할 길이 막혀버리지... 반쪽짜리 파이썬 스레드라고 해도, 블러킹 I/O 가 있을 경우에는 다른 스레드를 실행할 수 있게 해 주는데. 때문에 stackless 도 사용할 수 없단 얘기.

블러킹 I/O 와 넌블러킹 I/O 를 간단히 설명해 보면.. I/O 결과를 기다릴 때 해당 스레드가 멈춰 있느냐 계속 움직이느냐의 차이인데. scanf() 나 fread() 등등은 블러킹 I/O 의 가장 전형적인 예지. 데이터를 다 읽어온 후에야 함수가 반환되니까.. 반면 넌블러킹 I/O (Asynchronous I/O) 에서는 함수는 곧장 반환하고, 입출력이 끝나면 해당 스레드에 메시지나 시그널을 보내주는 형식으로 구현되지.. 이거는 결국 운영체제 차원에서 지원할 수밖에 없는데 윈도우의 IOCP, 리눅스의 epoll, BSD 의 kqueue 같은 게 있고.. 특히나 네트워크 같은 경우 CPU 보다 한없이 느리기 때문에, 넌블러킹 I/O 를 잘 이용해서 CPU 자원을 최대한 활용할 수 있도록 하는 게 중요하지.. 그래서 각종 네트워크 라이브러리 (루비의 이벤트머신, 파이썬의 트위스티드, C++ 의 ACE-_-; 와 부스트의 asio, 자바의 네티 등등..) 에서는 이런 것들을 거의 다 지원하고 있지.

다른분들 틀린거 있음 지적바랍니다. 'ㅅ' 맥주 먹었더니 알딸딸 아 자야지

2010-01-24 17:43:00 | JM | /quickpost/ | 11 Comments
hyoseung
2010-01-25 01:00:18
1. 네트워크가 느려서 넌블러킹 I/O를 쓴다기 보단, 스레드 비용이 크다보니 그런거임.
2. 가상 스레드 -> 유저레벨 스레드. 근데 딱히 유저레벨 스레드 구현물들이 스레드에 뭔가 특별한 제약사항을 두지 않는다면(ex, floating point 사용금지), 부하를 줄이는데 중점을 둔다 해도 효과는 미비할거야 -ㅁ-
JM
2010-01-25 04:22:10
1. 오오 valid points 감사. 블러킹 I/O 는 스레드를 이용해야 함 => 스레드 비용이 큼 => CPU 자원을 효율적으로 활용 불가능 이 되겠군. 비는 부분을 잘 채워주셨네 'ㅅ'
2. 파이썬의 경우 VM 에서 지원하는 스레드가 비교적 무거운 편이라 가상 스레드 비용이 작은 점이 두드러진다고 하네. 근데 특정 스레드에서 floating point 사용금지하는게 가능한가? -_-;;
3. 내가 정신 없다 보니 안 썼는데, 메시지 기반 프로그래밍을 택하는 이유는 기존 스레드+락기반 코드보다 훨씬 구현하기 쉽기 때문임. 데드락의 가능성도 적고.
JM
2010-01-25 04:24:10
파이썬 스레드의 무게에 관해.. GIL contention 에 관한 링크: http://www.dabeaz.com/blog/2010/01/python-gil-visualized.html GIL 은 파이썬 스레드 전체에 걸려있는 락인데, 파이썬 코드가 실행되려면 이 락을 잡아야 돼서 엄청난 컨텐션이 있음. => 같은 멀티스레드 프로그램이 듀얼코어에서 더 느림 -_-;
hyoseung
2010-01-25 10:31:31
링크를 읽어보니 파이썬 스레드는 커널레벨 스레드(OS 수준의 스레딩)를 쓰나보네. 근데 쟤가 기술한 ppt를 잠깐 봤는데, ppt안에 설명된 실행구조가 맞다면, 다른 이유가 있는진 모르겠지만... 설계 너무 심한데? -_-;;;;;;;;
저런 상황이라면, 일반적으로 생각하는 유저레벨스레드vs커널레벨스레드의 무게보다, 파이썬VM의 스레드는 무게가 훨씬 심할 수 밖에. 어떤 스레드가 블로킹 되어있어도, 스케줄링을 os에 의존하다보니 상대 스레드의 상태정보를 알 수 없어서 무작정 깨운다자나. 그럼 뭐 블로킹된 스레드는 깼다 다시 자는걸 반복하겠고... 성능은 당연히 떨어질 수 밖에. 파이썬VM같은 상황은 좀만 손봐도 크게 개선될거 같은데, 왜 안하는거지, 아님 내가 뭘 빠뜨린건가..?
아참, 그리고 특정스레드에서 floating point를 사용금지 한다는건... 유저레벨 스레드를 응용프로그램 차원에서 구현한다면 스케줄링도 유저프로그램 내에서 자체 구현해야하는데, 이때 컨텍스트 스위칭 시에 floating point같은건 무시하고 간단한 몇가지 레지스터만 저장/복원하는식으로 구현할수 있단 의미. 이러면 시스템콜도 안쓰고, 컨텍스트의 양 자체가 적어지니 빠르겠지 ㅎㅎ
첨언) 히스토리를 따져보면, 메시징 기반(이벤트 드리븐) 방식이 첨부터 쉽다고 여겨진건 아냐. 사실 스레드 기반 프로그래밍에서도 글로벌 락을 걸어버리면-_- 구현은 쉽자나? 이벤트 기반 프로그래밍은 stack ripping을 유발하기 때문에 오히려 시퀀셜한 프로그램을 짜기에 구현이 어렵다는게 전통적 관점;; 요새야 MFC도 이벤트다보니 이벤트기반에 적응한 프로그래머들이 많지만 ㅋㅋ
scheme
2010-01-25 11:10:19
설마 Symbian의 AO같은 거지같은 구조는 아니겠지요~~
hyoseung
2010-01-25 11:40:56
근데 애초에 이벤트 기반 프로그램에서, 이벤트 핸들러 내에서 블로킹을 한다는 것 자체가 문제인듯 -_-; 파이썬VM외부에 알고스팟 저징용 컴파일링이나 이런거를 시퀀셜하게 처리하는 큐잉 시스템을 하나 만들고, IPC로 파이썬과 통신하도록은 구성 못하나? (처리요청 -> 처리 완료 알림) 이렇게 phase를 분리하면 stackless python을 써도 무방할거 같은데...
JM
2010-01-25 15:04:42
@hyoseung/ 와 ㅋㅋㅋ 회사 출근하더니 이런 장문의 리플을 ㅋㅋㅋㅋ procrastination 의 힘이 대단하구만 그래. ㅋㅋ

1. CPython 의 스레드 구현은.. 하하.. 안습이지. -_-; 파이썬의 공식적인 입장은 무려 '스레드 쓰지 말고 멀티프로세스를 이용하시죠 ㅇㅅㅇ' 라는.. -_- 덕분에 무려 멀티프로세스를 스레드 인터페이스로 쓸 수 있는 표준 라이브러리가 있음.
2. 정정하자면, 블로킹된 스레드를 OS 가 깨운다는 것은 아니고, GIL 이 없는 스레드를 OS 가 깨운다는 것임. 설마 블로킹 시스템 콜 땜에 블록되어 있는 스레드를 깨울까.
3. GIL 같은 경우에는 CPython 초기에 구현을 간단히 하기 위해 선택한 구현 방식인데, 지금은 많은 양의 코드가 GIL 을 전제로 해서 작성되어 있어서 바꾸기도 어렵다고 하네. 실제로 바꾸려는 시도는 몇 번 있었는데, 이와 같은 fine-grained lock 의 경우에 싱글코어에서의 성능이 매우 떨어지는 문제 때문에 포기했다고 함. (너가 얘기한대로, 스레드 기반 프로그램에서 글로벌 락 걸어서 구현 쉽게 했다가 좆되고 있는 사례라고 보면 됨.)
4. 그러니까 플로팅 포인트 레지스터는 컨텍스트에 안 넣는다는 건가? ㅋㅋㅋㅋㅋ 쩌는뎅? ㅋㅋㅋㅋ
5. 그게 문제인 거 같긴 한데 사실 이벤트 기반 I/O 란게 구현하기가 워낙 까다로워야지. 파이썬 같은 경우 twisted 란 라이브러리에서 이와 같은 것들을 구현해 주고 있긴 한데 규모가 너무 커서 나같은 소규모 프로젝트에서는 배보다 배꼽이 더 큰 위기
6. 흐흐, 그럴듯하긴 한데 그것도 좀 배꼽이 큰 거 같다. 여튼 난 결과적으로 최소한의 기능만 제공하는 thread-backed event driven actor class 를 짜서 넘어갔음. 그냥 이벤트 핸들러 내에서 블로킹 해버림 ㅋㅋㅋㅋ 어떻게든 타임아웃을 다 걸긴 했지만 커흙~

여튼 실한 리플 ㄱㅅㄱㅅ :-)

@scheme, 아니 s모전자 symbian 팀에서 일하시던 s 모씨 여기서 이러시면 곤란합니다. ㅋㅋ 구조 가 어떻길래? AO 가 뭔데? ㅋㅋ
hyoseung
2010-01-25 15:59:12
회사에 오니 인터넷에 집중하는 효과?! ㅋㅋㅋ 2번은 내가 말을 잘못한듯 ㅋㅋㅋㅋ
근데 굳이 fine-grained locking으로 파이썬 코드를 싸그리 뜯어고치지 않더라도, 파이썬VM이 스레드 실행에 조금만 관여해도 멀티프로세서에서 성능이 확 떨어지진 않을듯.
JM
2010-01-26 12:41:31
@hyoseung 그래 너가 파이썬 커미터가 되는거다!
dg
2010-01-26 14:40:33
Stackless Python 링크가 http://stackless.org/ 로 걸려있는데 http://www.stackless.com/ 가 맞는듯...
JM
2010-01-26 14:49:58
@dg 앗 ㅈㅅㅈㅅ 고치겠음

Leave a comment