동기와 비동기는 요청의 결과 처리 시점과 요청의 결과 반환 시점의 일치/불일치 여부에 따라 동기/비동기로 나뉘어지게 됩니다. 설명하기 앞서 요청을 하는 주체를 사용자 프로그램(사용자), 요청을 받아 처리하는 주체를 커널(시스템)으로 설정하겠습니다.
동기는 사용자가 시스템에게 I/O와 같은 작업을 요청하고, 해당 요청의 처리 결과가 반환되면 즉시 해당 결과를 가지고 작업을 수행하게 됩니다. 반면 비동기의 경우, 반환된 결과를 처리하는 시점이 반환 시점과 일치하지 않을 수 있습니다.
이처럼 요청의 결과를 처리하는 시점이 결과를 반환하는 시점과 반드시 일치하게되면 동기, 반드시 일치하지 않아도 된다면 비동기입니다.
블록과 논블록은 요청한 사용자의 실행 제어권을 막느냐, 막지 않느냐에 따라 나뉘어지게 됩니다. 블록의 경우 사용자가 시스템에 작업을 요청하게되면 사용자의 실행 제어권이 막히게되어 다른 연산을 수행하지 못하게 됩니다. 반면 논블록의 경우 실행의 제어권이 막히지 않기 때문에 시스템에 요청을 보낸 후, 다른 연산을 수행할 수 있게 됩니다.
동기 블록 방식은 제일 많이 사용되는 방식입니다. 구현하기 간단하고 직관적인 장점이 있으나 효율성이 떨어지게 됩니다. 동기 블록이 어떠한 방식으로 동작하는지 아래의 예시를 보며 설명하겠습니다.
사용자 프로그램이 어떤 파일을 읽기 위해 read
함수를 호출하였습니다. 해당 함수는 커널로 전달되고, 커널은 파일 시스템에서 해당 파일을 읽어온 뒤, 파일을 다시 사용자 프로그램에게 전달하게 됩니다.
파일을 읽기 위해 read
함수를 호출한 사용자 프로그램은 read
를 호출한 순간부터 실행을 멈추며 블록됩니다. 그리고 I/O 작업이 완료될때까지 기다린 후, 커널에서 I/O 처리 결과를 반환하게 되면 해당 결과를 바로 처리하게 됩니다.
동기 블록은 호출 구조와 구현 방식이 간단하기 때문에 많이 사용됩니다. 또한 일반적인 로직에서는 블록되는 시간이 매우 짧기 때문에 그냥 동기 블록 방식을 사용하기도 합니다. 하지만 사용자 프로그램이 I/O 연산에 의존하여 동작을 멈추기 때문에 효율적인 방식이라고는 할 수 없습니다.
동기 논블록 방식은 상황에 따라 동기 블록보다 비효율적으로 동작할 수 있습니다.
사용자 프로그램이 read
함수를 호출한 다음, 자신의 동작을 이어 실행하며 커널에 주기적으로 signal
을 보내 요청의 처리 결과를 확인하게 됩니다. 커널은 전달받은 read
동작에 따라 I/O 동작을 수행하며 요청이 처리되지 않았다면 처리되지 않았다는 응답을, 처리가 되었다면 해당 요청의 처리 결과를 반환하게 됩니다. 사용자 프로그램은 커널로부터 처리되지 않았다는 응답을 받게되면 다시 다른 동작을 수행하고, 처리 결과를 받게되면 해당 결과를 바로 처리하게 됩니다.
비동기의 경우 커널의 응답을 즉각적으로 처리하지 않을 수 있습니다.
사용자 프로그램이 커널에게 read
를 요청하게되면 커널은 I/O 작업을 요청하고 사용자 프로그램에게 wait signal
을 보내게 됩니다. wait signal
을 받은 사용자 프로그램은 커널이 다시 signal
을 보낼때까지 동작을 멈추고 기다리게 됩니다.
커널은 I/O 동작이 완료되면 사용자 프로그램에게 response signal
을 통해 요청의 처리 완료 여부를 전달하게 됩니다. 그러면 사용자 프로그램은 요청의 처리 결과를 요청하여 커널로부터 처리 결과를 받게 됩니다. 이와 같은 비동기 블록은 소켓 통신에서 커넥션을 맺고 기다리는 과정에서 많이 사용됩니다.
비동기 논블록 방식의 경우, 사용자 프로그램이 커널에게 요청을 보내고 다른 동작을 수행합니다. 커널은 사용자 프로그램으로부터 받은 요청을 처리하고, 완료되면 사용자 프로그램에게 해당 처리의 결과를 반환하게 됩니다. 사용자 프로그램은 커널로부터 받은 처리 결과를 확인한 다음 구현된 방법에 따라 처리하게 됩니다.
비동기 논블록의 경우 위의 4가지 방법중 가장 효율적인 방식이라고 알려져있지만 구현된 로직에 따라 생각만큼 효율적이지 않을 수 있습니다. 이런 구조를 구현하기 위해서는 몇가지 작업을 수행해야하는데, I/O 작업 작체가 매우 빠른 작업이라면 비동기 논블록 방식보다는 동기 블록이 빠르게 동작할 수 있습니다.
따라서 가장 효율적인 방법은 사용하려는 환경과 목적에 따라 다를 수 있습니다. 이러한 요인들을 고려하여 환경과 목적에 따른 기술을 사용하여 구현하는 것이 중요합니다.