비동기 호출과 비 차단 호출의 차이점은 무엇입니까? 또한 차단과 동기 호출 사이에 (예제를 사용하십시오)?
비동기 호출과 비 차단 호출의 차이점은 무엇입니까? 또한 차단과 동기 호출 사이에 (예제를 사용하십시오)?
답변:
많은 상황에서 그것들은 같은 것에 대해 다른 이름이지만, 어떤 상황에서는 상당히 다릅니다. 따라서 다릅니다. 용어는 전체 소프트웨어 산업에서 완전히 일관된 방식으로 적용되지 않습니다.
예를 들어 기존 소켓 API에서 비 차단 소켓은 특별한 "차단할 것"오류 메시지와 함께 즉시 반환되는 반면, 차단 소켓은 차단 된 소켓입니다. 재 시도하기에 적합한시기 select
또는 poll
찾기 와 같은 별도의 기능을 사용해야합니다 .
그러나 비동기 소켓 (Windows 소켓에서 지원) 또는 .NET에서 사용되는 비동기 IO 패턴이 더 편리합니다. 메소드를 호출하여 조작을 시작하면 프레임 워크가 완료되면 다시 호출합니다. 여기에도 기본적인 차이점이 있습니다. 비동기 Win32 소켓은 Window 메시지를 전달하여 결과를 특정 GUI 스레드에 "마샬링"하는 반면 .NET 비동기 IO는 자유 스레드 (콜백을 호출 할 스레드를 모릅니다).
따라서 항상 같은 의미는 아닙니다. 소켓 예제를 공개하기 위해 다음과 같이 말할 수 있습니다.
동기식 / 비동기식은 두 모듈 간의 관계를 설명하는 것입니다.
차단 / 비 차단은 하나의 모듈의 상황을 설명하는 것입니다.
예 :
모듈 X : "I".
모듈 Y : "서점".
X는 Y에게 묻습니다. "c ++ primer"라는 책이 있습니까?
1) 차단 : Y가 X에 응답하기 전에 X는 응답을 기다립니다. 이제 X (하나의 모듈)가 차단되고 있습니다. X와 Y는 두 개의 스레드 또는 두 개의 프로세스 또는 하나의 스레드 또는 하나의 프로세스입니까? 우리는 모른다.
2) 비 차단 : Y가 X에 응답하기 전에 X는 그냥 떠나서 다른 일을합니다. Y가 작업을 완료했는지 확인하기 위해 2 분마다 X가 다시 나타날 수 있습니까? 아니면 Y가 전화 할 때까지 X가 돌아 오지 않습니까? 우리는 모른다. 우리는 Y가 일을 끝내기 전에 X가 다른 일을 할 수 있다는 것을 알고 있습니다. 여기서 X (하나의 모듈)는 비 차단입니다. X와 Y는 두 개의 스레드 또는 두 개의 프로세스 또는 하나의 프로세스입니까? 우리는 모른다. 그러나 우리는 X와 Y가 하나의 스레드가 될 수 없다고 확신합니다.
3) 동기식 : Y가 X에 응답하기 전에 X는 응답을 계속 기다립니다. 이는 Y가 작업을 마칠 때까지 X를 계속할 수 없음을 의미합니다. 이제 우리는 말합니다 : X와 Y (두 모듈)는 동 기적입니다. X와 Y는 두 개의 스레드 또는 두 개의 프로세스 또는 하나의 스레드 또는 하나의 프로세스입니까? 우리는 모른다.
4) 비동기 : Y가 X에 응답하기 전에 X가 떠나고 X는 다른 작업을 수행 할 수 있습니다. Y가 전화 할 때까지 X는 돌아 오지 않습니다. 이제 우리는 말합니다 : X와 Y (두 모듈)는 비동기입니다. X와 Y는 두 개의 스레드 또는 두 개의 프로세스 또는 하나의 프로세스입니까? 우리는 모른다. 그러나 우리는 X와 Y가 하나의 스레드가 될 수 없다고 확신합니다.
위의 두 가지 굵은 문장에주의하십시오. 2)의 굵은 문장은 왜 2 개의 사례를 포함하고 4)의 굵은 문장은 하나의 사례 만 포함합니까? 이것이 비 차단과 비동기의 차이점의 핵심입니다.
비 차단 및 동기에 대한 일반적인 예는 다음과 같습니다.
// thread X
while (true)
{
msg = recv(Y, NON_BLOCKING_FLAG);
if (msg is not empty)
{
break;
}
sleep(2000); // 2 sec
}
// thread Y
// prepare the book for X
send(X, book);
이 디자인은 비 블로킹임을 알 수 있습니다 (대부분이 루프는 말도 안되는 일을하지만 CPU의 눈에는 X가 실행 중이므로 X는 비 블로킹을 의미합니다) .X는 X가 Y에서 책을 얻을 때까지 다른 일을 계속하지 마십시오 (X는 루프에서 뛰어 넘을 수 없습니다).
이 경우 일반적으로 비 차단은 바보 같은 루프에 많은 리소스를 소비하기 때문에 X 차단이 훨씬 좋습니다. 그러나이 예는 사실을 이해하는 데 도움이됩니다. 비 차단은 비동기를 의미하지 않습니다.
네 단어는 우리를 쉽게 혼란스럽게 만듭니다. 우리가 기억해야 할 것은 네 단어가 건축 설계에 도움이된다는 것입니다. 좋은 아키텍처를 디자인하는 방법을 배우는 것이이를 구별하는 유일한 방법입니다.
예를 들어, 우리는 그런 종류의 아키텍처를 설계 할 수 있습니다 :
// Module X = Module X1 + Module X2
// Module X1
while (true)
{
msg = recv(many_other_modules, NON_BLOCKING_FLAG);
if (msg is not null)
{
if (msg == "done")
{
break;
}
// create a thread to process msg
}
sleep(2000); // 2 sec
}
// Module X2
broadcast("I got the book from Y");
// Module Y
// prepare the book for X
send(X, book);
여기 예제에서 우리는 말할 수 있습니다
필요한 경우 X1에서 작성된 스레드를 네 단어로 설명 할 수도 있습니다.
더 중요한 것은 : 비동기 대신 동기를 언제 사용합니까? 비 차단 대신 언제 차단을 사용합니까?
Nginx가 왜 차단되지 않습니까? Apache가 왜 차단됩니까?
올바른 선택을하려면 요구 사항을 분석하고 다양한 아키텍처의 성능을 테스트해야합니다. 다양한 요구에 적합한 아키텍처는 없습니다.
자바 7에서 NIO와 NIO.2의 맥락 에서이 질문을하면 비동기 IO는 비 블로킹보다 한 단계 앞선 것입니다. Java NIO 비 차단 호출의 경우을 호출하여 모든 채널 (SocketChannel, ServerSocketChannel, FileChannel 등)을 설정합니다 AbstractSelectableChannel.configureBlocking(false)
. 그러나 이러한 IO 호출이 반환 된 후에도 언제 다시 읽고 쓰는지 등의 검사를 제어해야 할 수 있습니다.
예를 들어,
while (!isDataEnough()) {
socketchannel.read(inputBuffer);
// do something else and then read again
}
Java 7의 비동기 API를 사용하면 이러한 컨트롤을보다 다양한 방법으로 만들 수 있습니다. 두 가지 방법 중 하나를 사용하는 것 CompletionHandler
입니다. 두 read
통화는 모두 차단되지 않습니다.
asyncsocket.read(inputBuffer, 60, TimeUnit.SECONDS /* 60 secs for timeout */,
new CompletionHandler<Integer, Object>() {
public void completed(Integer result, Object attachment) {...}
public void failed(Throwable e, Object attachment) {...}
}
}
FileChannel
를 선택할 수 없으며 비 차단으로 구성 할 수 없습니다.
당신이 아마 다른 (그리고 종종 상호 배타적 인) 수많은 답변에서 볼 수 있듯이, 그것은 당신이 묻는 사람에 달려 있습니다. 어떤 분야에서는 용어가 동의어입니다. 또는 두 가지 유사한 개념을 각각 참조 할 수 있습니다.
두 경우 모두, 느린 프로세스가 완료되기를 기다리는 동안 프로그램이 차단되지 않도록하는 것입니다. 프로그램의 응답 방식이 유일한 차이입니다. 어떤 용어는 프로그래머에서 프로그래머로, 언어에서 언어로, 또는 플랫폼에서 플랫폼으로 변경되는 것을 말합니다. 또는이 용어는 완전히 다른 개념 (예 : 스레드 프로그래밍과 관련하여 동기식 / 비동기식 사용)을 나타낼 수 있습니다.
미안하지만 전 세계적으로 맞는 단일 답변이 있다고 생각하지 않습니다.
블로킹 즉시 어떤 데이터 호출이 반환을 사용할 수 있습니다 바이트의 전체 수는 적은 요청하지 않거나 전혀 없음.
비동기 호출은 전체 (전체)에서 수행되지만 미래의 어느 시간에 완료 전송을 요청합니다.
비 차단 :이 기능은 스택에있는 동안 기다리지 않습니다.
비동기 : 호출이 스택을 떠난 후 함수 호출 대신 작업이 계속 될 수 있습니다.
동기 는 동시에 발생하는 것으로 정의됩니다.
비동기 는 동시에 발생하지 않는 것으로 정의됩니다.
이것이 첫 혼동의 원인입니다. 동기는 실제로 병렬이라고합니다. 비동기식은 순차적이지만이를 수행 한 다음 수행하십시오.
이제 전체 문제는 비동기 동작을 모델링하는 것입니다. 시작하기 전에 다른 응답이 필요한 작업이 있기 때문입니다. 따라서 조정 문제입니다. 이제 해당 작업을 시작할 수 있다는 것을 어떻게 알 수 있습니까?
가장 간단한 솔루션을 차단이라고합니다.
차단 은 다른 작업이 완료 될 때까지 기다렸다가 필요한 작업으로 이동하기 전에 응답을 반환하는 것입니다.
따라서 토스트에 버터를 넣어야한다면 먼저 번식을 토스트해야합니다. 당신이 그들을 조정하는 방법은 먼저 번식을 토스트 한 다음 토스트가 터질 때까지 토스터를 끝까지 쳐다 본 다음 버터를 바르는 것입니다.
가장 간단한 솔루션이며 매우 잘 작동합니다. 작업과 조정이 필요하지 않은 다른 작업을 수행하지 않는 한 사용하지 않는 실제 이유는 없습니다. 예를 들어, 요리를하는 것. 토스트가 튀어 나올 때까지 계속 토스터를 쳐다 보는 유휴 상태를 유지하는 이유는 무엇입니까?
비 블로킹 및 비동기로 각각 알려진 다른 두 가지 솔루션이 사용됩니다.
비 차단 은 작업이 완료되기를 기다리는 동안 관련없는 다른 작업을 수행하도록 선택한 경우입니다. 적절하다고 생각되는 응답의 가용성을 다시 확인하십시오.
그래서 토스터를 보는 대신에 터지는 것. 가서 전체 접시를 씻으십시오. 그런 다음 토스트가 튀어 나왔는지 확인하기 위해 토스터를 들여다 봅니다. 그들이 아직 없다면, 다른 접시를 씻고 각 접시 사이의 토스터를 다시 확인하십시오. 토스트가 터지는 것을 보았을 때 설거지를 멈추고 대신 토스트를 바르고 버터를 바르십시오.
그래도 토스트를 계속 확인해야한다면 성가신 일이 될 수 있습니다. 토스터가 다른 방에 있다고 상상해보십시오. 요리 사이에서 토스트를 확인하기 위해 다른 방으로가는 시간을 낭비합니다.
여기 비동기식이 제공됩니다.
비동기 는 작업이 완료되기를 기다리는 동안 관련없는 다른 작업을 수행하도록 선택한 경우입니다. 그러나 확인하는 대신 확인 작업을 다른 것으로 위임하고 작업 자체 또는 감시자가 될 수 있으며 응답이 사용 가능할 때 알림을 제공하고 방해하여 다른 작업으로 진행할 수 있습니다. 필요했습니다.
이상한 용어입니다. 이러한 모든 솔루션은 종속 작업의 비동기 조정을 생성하는 방법이기 때문에 전혀 이해가되지 않습니다. 그것이 내가 이벤트라고 부르는 것을 선호하는 이유입니다.
따라서이 경우 토스트가 완료되면 경고음을 내도록 토스터를 업그레이드하기로 결정합니다. 설거지를하는 동안에도 계속 듣습니다. 경고음이 들리면 현재 접시를 씻는 즉시 멈추고 버터를 토스트에 넣으십시오. 또는 현재 접시의 세척을 방해하고 토스트를 즉시 처리하도록 선택할 수 있습니다.
경고음이 잘 들리지 않으면 파트너가 토스터를보고 토스트가 준비되면 알려주십시오. 파트너는 위의 세 가지 전략 중 하나를 선택하여 토스터를보고 준비가되면 알려주는 작업을 조정할 수 있습니다.
마지막으로, 비 차단 및 비동기 (또는 내가 이벤트라고 부르는 것을 선호 함)는 기다리는 동안 다른 작업을 수행 할 수 있지만 그렇지 않다는 것을 이해하는 것이 좋습니다. 비 차단 통화 상태를 지속적으로 확인하고 다른 작업은 수행하지 않도록 선택할 수 있습니다. 그것은 종종 블로킹보다 나쁘다 (토스터를보고 나서 멀리하고 다시 끝날 때까지). 많은 비 블로킹 API를 사용하면 블로킹 모드로 전환 할 수 있습니다. 이벤트가 발생하면 알림을받을 때까지 유휴 상태 일 수 있습니다. 이 경우 단점은 알림을 추가하는 것이 복잡하고 잠재적으로 비용이 많이 든다는 것입니다. 경고음 기능이있는 새 토스터를 구입하거나 파트너가 보도록 설득해야했습니다.
그리고 한 가지 더, 당신은 세 가지 모두가 제공하는 트레이드 오프를 실현해야합니다. 하나는 분명히 다른 것보다 낫지 않습니다. 내 예를 생각해보십시오. 토스터가 너무 빠르면 설거지를 할 시간이없고 설거지를하지 않아도되므로 토스터가 얼마나 빠릅니다. 이 경우 다른 작업을 시작하면 시간과 노력이 낭비됩니다. 차단합니다. 마찬가지로, 설거지를 할 때 건배 시간보다 10 배 더 오래 걸립니다. 해야 할 일이 더 중요한지 스스로에게 물어봐야합니까? 그 때까지 건배가 차갑고 단단해질 수 있습니다. 또는 기다리는 동안해야 할 일을 더 빨리 선택해야합니다. 더 분명하지만 내 대답은 이미 꽤 길었습니다. 제 요점은 모든 것을 생각하고 가치가 있는지 여부를 결정하기 위해 각각을 구현하는 복잡성에 대해 생각해야한다는 것입니다.
편집하다:
이것이 이미 길지만 완료되기를 원하므로 두 점을 더 추가 할 것입니다.
1) 일반적으로 다중화로 알려진 네 번째 모델이 있습니다 . 한 작업을 기다리는 동안 다른 작업을 시작하고 두 작업을 기다리는 동안 다시 시작하는 등 많은 작업이 모두 시작된 다음 유휴 대기하지만 그들. 따라서 작업이 완료되면 응답 처리를 진행 한 다음 다른 작업을 기다리는 것으로 돌아갈 수 있습니다. 기다리는 동안 각 작업을 하나씩 확인하여 작업이 완료 될 때까지 광고가 완료되었는지 확인해야하기 때문에 멀티플렉싱이라고합니다. 일반적인 비 차단 기능을 약간 확장 한 것입니다.
이 예에서는 토스터, 식기 세척기, 전자 레인지 등을 시작한 다음 대기하는 것과 같습니다. 토스터를 점검 한 경우 토스터가 있는지 확인하십시오.
2) 큰 실수라고 생각하지만 동기는 종종 한 번에 한 가지를 의미하는 데 사용됩니다. 그리고 한 번에 많은 것들을 비 동기화하십시오. 따라서 차단 및 비 차단을 나타내는 데 동기식 차단 및 비 차단이 사용됩니다. 다중화 및 이벤트를 나타내는 데 사용되는 비동기 차단 및 비 차단.
나는 우리가 어떻게 거기에 도착했는지 이해하지 못한다. 그러나 IO 및 계산과 관련하여 동기 및 비동기는 종종 겹치지 않고 겹치는 것으로 더 잘 알려진 것을 말합니다. 즉, 비동기는 IO와 계산이 일관되게 겹치는 것을 의미합니다. 동기는 그렇지 않다는 것을 의미하므로 순차적으로 발생합니다. 동기식 비 차단의 경우 다른 IO 또는 계산을 시작하지 않고 대기 중이며 차단 호출을 시뮬레이션합니다. 나는 사람들이 그와 같이 비동기적이고 비동기 적으로 오용하는 것을 멈추기를 바란다. 그래서 나는 그것을 장려하지 않습니다.
통화 차단 : 통화가 완료된 경우에만 제어가 반환됩니다.
비 차단 통화 : 제어가 즉시 반환됩니다. 나중에 OS는 호출이 완료되었음을 프로세스에 알립니다.
동기 프로그램 : 차단 호출 을 사용하는 프로그램 . 호출 중에 멈추지 않으려면 2 개 이상의 스레드가 있어야합니다 (동기화-스레드가 동 기적으로 실행되는 이유).
비동기 프로그램 : 비 차단 호출 을 사용하는 프로그램 . 스레드는 하나만 가질 수 있으며 여전히 대화식으로 유지됩니다.
블로킹 : 기본 (동기화 또는 비동기) 처리가 완료된 후 제어가 호출 전진으로 돌아갑니다 .
비 차단 : 제어는 호출 직후 처리로 돌아갑니다 .