IO 처리(소켓이나 파일, 파이프 등등)에는 블록, 논블록, 비동기(뒤에 두개는 거의 같은 계념인데 문맥만 약간 다릅니다)가 있습니다. 큰 차이는 스레드가 기다리느냐, 기다리지 않느냐인데
블록킹은 말 그대로 막힘니다. 즉, 스레드가 논리 버퍼(파일 시스템, 하드웨어 같은 저급버퍼가 아니라)에 있는 데이터가 모두 처리될 때 까지 기다림니다. 이걸 유닉스 진형에서 "io wait"이라고 합니다. 문맥상으로는 처리이나 실제로는 스케듈러가 CPU시간을 안 주는. 유닉스 설계 당시에는 이 방법이 유일했습니다.
논블럭은 그 반대라고 생각하심 돼요. 스레드가 처리할 데이터를 버퍼에다만 큐하고 다른 중요한 일을 처리하는 겁니다. 이 떄 하드나 네트워크 인터페이스는 열심히 돌고 있겠죠.
뭐, 비동기도 똑같은데, 다른 점이 있다면 그 '처리의 결과'를 확인하는 방법이 다릅니다. 이건 OS마다 정의가 중구남방이니 굳이 기술 안 합니다.
걍 뭐하러 동기만 쓰지 왜 비동기가 나왔느냐? 이 블록킹 처리의 비효율 때문입니다. 논블록의 패턴이 가지는 장점 또한 있구요.
이건 'C10K 문제' 를 찾아보시면 더 많은 정보를 얻으실 수 있습니다. 많은 IO를 동시에 처리해야 할 수록 블록킹 IO는 스레드를 IO개수 만큼 만들어 줘야 했습니다.
엄청난 비효율이죠. 각 스레드가 다 쓰지도 않는 스택을 하나하나 고정적인 크기로 할당해 줘야하고, 스케듈러도 점점 힘든 소리를 내구요.
이건 확인된 결과인게, 그 어떤 시스템이건 스레드의 개수가 몇천개이면 하드웨어가 아무리 좋아도 정상적인 처리가 힘듭니다. 메모리도 비효율적이구요. 이걸 병목현상이라고 하더군요.
핵심은 한 스레드로 여러 IO를 동시에 처리할 수 있다는 겁니다. select()나 poll() 같은 함수로 처리해야 할 IO들만 뽑아서 효율적으로 처리한다는 거죠.
이벤트 처리나 버퍼 오버플로, 타임아웃 등 처리해야 할 것들이 많아지면서 연산량에서 손실을 약간 보긴 하지만 스레드를 마구 생성해야 하는 오버헤드보다는 횔 나은거에요.
현대, 밀레니엄 이후의 무게있는 서버 프로그램들은 대부분 이렇게 작성됩니다.
솔직히 posix 스레드보다는 Win32 스레드가 성능이 더 좋아서 윈도우 환경에서는 걍 개념없이 블럭킹 모델로 설계를 해도 그리 문제가 되진 않습니다.
posix 스레드를 사용한다면 피할 수 없는 문제.
소프트웨어 한계 때문에 나온 것들인데
굳이 WSA* (아마 윈도에서 제공하는 소켓?)에 국한되는 질문이 아닙니다.
IO 처리(소켓이나 파일, 파이프 등등)에는 블록, 논블록, 비동기(뒤에 두개는 거의 같은 계념인데 문맥만 약간 다릅니다)가 있습니다. 큰 차이는 스레드가 기다리느냐, 기다리지 않느냐인데
블록킹은 말 그대로 막힘니다. 즉, 스레드가 논리 버퍼(파일 시스템, 하드웨어 같은 저급버퍼가 아니라)에 있는 데이터가 모두 처리될 때 까지 기다림니다. 이걸 유닉스 진형에서 "io wait"이라고 합니다. 문맥상으로는 처리이나 실제로는 스케듈러가 CPU시간을 안 주는. 유닉스 설계 당시에는 이 방법이 유일했습니다.
논블럭은 그 반대라고 생각하심 돼요. 스레드가 처리할 데이터를 버퍼에다만 큐하고 다른 중요한 일을 처리하는 겁니다. 이 떄 하드나 네트워크 인터페이스는 열심히 돌고 있겠죠.
뭐, 비동기도 똑같은데, 다른 점이 있다면 그 '처리의 결과'를 확인하는 방법이 다릅니다. 이건 OS마다 정의가 중구남방이니 굳이 기술 안 합니다.
걍 뭐하러 동기만 쓰지 왜 비동기가 나왔느냐? 이 블록킹 처리의 비효율 때문입니다. 논블록의 패턴이 가지는 장점 또한 있구요.
이건 'C10K 문제' 를 찾아보시면 더 많은 정보를 얻으실 수 있습니다. 많은 IO를 동시에 처리해야 할 수록 블록킹 IO는 스레드를 IO개수 만큼 만들어 줘야 했습니다.
엄청난 비효율이죠. 각 스레드가 다 쓰지도 않는 스택을 하나하나 고정적인 크기로 할당해 줘야하고, 스케듈러도 점점 힘든 소리를 내구요.
이건 확인된 결과인게, 그 어떤 시스템이건 스레드의 개수가 몇천개이면 하드웨어가 아무리 좋아도 정상적인 처리가 힘듭니다. 메모리도 비효율적이구요. 이걸 병목현상이라고 하더군요.
핵심은 한 스레드로 여러 IO를 동시에 처리할 수 있다는 겁니다. select()나 poll() 같은 함수로 처리해야 할 IO들만 뽑아서 효율적으로 처리한다는 거죠.
이벤트 처리나 버퍼 오버플로, 타임아웃 등 처리해야 할 것들이 많아지면서 연산량에서 손실을 약간 보긴 하지만 스레드를 마구 생성해야 하는 오버헤드보다는 횔 나은거에요.
현대, 밀레니엄 이후의 무게있는 서버 프로그램들은 대부분 이렇게 작성됩니다.
솔직히 posix 스레드보다는 Win32 스레드가 성능이 더 좋아서 윈도우 환경에서는 걍 개념없이 블럭킹 모델로 설계를 해도 그리 문제가 되진 않습니다.
posix 스레드를 사용한다면 피할 수 없는 문제.
댓글 달기