본문 바로가기

그 외

블럭(block)과 논블럭(non-block), 동기(sync)와 비동기(async)

728x90

상당히 어렵고 생각할수록 혼란스러운 주제다. 많이 언급되지만 개념적으로 명확하게 내려진 정의라고 해야할지 획일화된 정의라고 느껴지는 글은 없었고, 다들 나름의 정의 혹은 그저 누군가의 정의를 옮기기만 한 글이었다.

 

그래서 나도 다른 글들을 많이 읽으며 고심끝에 마찬가지로 나름대로 내가 이해하고 정의한 대로 풀어보려고한다.

때문에 매우매우매우 주관적이고, 다른 글들을 보고 내 글을 보면 더 느낌이 와닿을 수 있다.

 

간단한 개념 정의

상당히 많은 글들이 블럭/논블럭에서는 제어권, 동기/비동기는 결과값이라는 키워드를 많이 사용하고 있는데 맞는 말이지만, 개인적으로 코드적으로 얘기를 하는게 더 이해하기 쉽다고 생각해서 함수의 입장에서 풀어보려고 한다.

 

블럭과 논블럭

블럭

보통 함수 A 안에서 다른 함수 B를 호출한 경우에 B로 제어권이 넘어가서 다른일을 못하고 있을때 블럭이라고 표현한다.

개인적으로는 제어권이라기 보다 B가 끝낼때까지 A가 다른일을 못하고 가만히 있으면 블럭이라고 생각한다.

출처 : https://study-ihl.tistory.com/159

논블럭 

보통 함수 A 안에서 다른 함수 B를 호출한 경우에 B로 제어권이 갔다가 바로 다시 제어권을 리턴받아서 다른일이 가능한 경우에 논블럭 이라고 한다.

개인적으로 논블럭에서도 제어권이라기 보다는 내부에 호출된 B가 동작할때 A가 그 이후에 다른 어떠한 동작이라도 하게 된다면 논블럭이라고 생각한다.

 

출처 : https://study-ihl.tistory.com/159

 

즉 제어권을 기준으로 잡기 보다는, 함수 A의 관점에서 일을 할 수 있는지 못하는지를 기준으로 두는 것이다.

동기와 비동기

연속적으로 인과관계의 작업이 있다는 가정하에, 작업이 순차적으로 이루어지면 동기, 아니면 비동기라고 생각한다.

조금 더 코드적으로 얘기하면 한 함수 A안에 연속된 작업이 있다고 할때, 그 작업들에 콜백이 있으면 비동기, 없으면 동기라고 생각한다. 콜백이 있으면 순차적으로 이루어지지 않는다고 정의를 하기 때문이다.

 

블럭과 논블럭, 동기와 비동기의 조합을 코드로 구현할때 이 정의를 고려를 해야 이해가 수월하다.

 

블럭과 동기, 논블럭과 비동기가 왜 헷갈릴까?

원인으로는 내 기준의 2가지의 이유가 있다.

 

1. 블럭과 동기, 논블럭과 비동기는 명확히 다른 개념이지만 대립되는 개념이 아닌데 생각하면 할수록 무의식적으로 대립되는 구조로 보기 때문에

- 둘은 같은 영역관? 같은 관점에서 보는 개념이 아니라고 생각한다.

 

2. 각각의 개념에 대한 예시 코드를 보면 한가지만 들어있는 경우가 거의 없기 때문에

- 개인적으로 동기적 코드가 구현되면 블락이랑 일치하는 부분이 많고, 비동기적 코드가 구현되면 논블락이랑 일치하는 부분이 많기 때문이다. 심지어 두가지의 개념만 포함되있는게 아니라 짧은 예시코드에서도 어떻게 보면 여러 개념이 다 들어가있다. (어디는 동기, 어디는 비동기, 어떤부분은 블럭, 어떤부분은 논블럭의 식으로)

 

이 두가지 이유에 대해서는 각각의 4가지 조합을 본 후 다시 읽어보면 이해가 갈 것이다.

 

각각의 조합 4가지

흔해서 쉽게 와닿는 조합

동기와 블럭

웬만한 동기 예시 코드들은 거의 동기 x 블럭 조합의 예시코드다.

 

예시 코드

function B () {
	//엄청난 동작들
	return 어떤 결과;
}

function A () {
	B();
	console.log('aa');
	console.log('bb');
	console.log('cc');
}

대략 이렇게 생긴 코드로 쉽게 이해할 수 있다.

 

비동기와 논블럭

마찬가지로 웬만한 비동기 예시 코드들은 거의 비동기 x 논블럭 조합이다.

 

예시 코드

function B () {
	//엄청난 동작들
	return 어떤 결과;
}

function A () {
	setTimeout(B(), 3000);
	console.log('aa');
    //여기 까진 비동기 논블럭이어도
    
    //여기 부턴 동기 블럭상황이 될 수 있는건 마찬가지
	console.log('bb');
	console.log('cc');
}

사실 setTimeout -> console.log('aa')의 경우로 가는게 비동기이면서 논블럭인 상황이지

개인적인 생각으로는 함수 B의 동작타임에 따라 다르지만,

그 이후에 console.log들만 놓고 본다면, console.log가 아니라 오래걸리는 작업이라면

동기x블럭상황이 될 수 있는건 마찬가지라고 생각한다. 

=> 헷갈리는 이유 2번

 

흔하지 않아서 쉽게 와닿지 않는 조합

앞에서 말했던 동기/비동기, 블럭/논블럭의 정의에 대해 생각하며 해석해봤다.

 

동기와 논블럭

- 대부분의 다른 글들은 폴링방식의 코드를 예시로 든다. 왜 이 예시가 대표인지에 대해서 풀어보면

조금 감이 잡힌다.

 

설명에 있어서 위의 동기x블록 예시코드를 사용한다. 함수 A의 안에 함수 B를 호출하는 코드

function B () {
	//엄청난 동작들
	return 어떤 결과;
}

function A () {
	B();
	console.log('aa');
	console.log('bb');
	console.log('cc');
}

 

 

동기는 콜백이 없어야한다.

논블럭은 아무것도 못하고 있으면 안된다.

 

합쳐보면, 콜백이 없는데 내부에 호출한 함수 동작의 스탑이 없는 상황이 동기x논블럭 조합이다.

그러면 동작의 스탑이 있는 이유는 대게 내부 호출 함수의 동작 완료가 필요하기 때문인데

(동기는 데이터를 일치시키는 개념이니까) 

동기는 콜백이 없기 때문에 이런 상황이 만들어 지기 위해선 당연히 폴링 방법 밖에 없다.

 

즉, 내부 함수 B의 결과 값에 대해 얻기 위해서는 콜백이 없으면 당연히 A입장에선 폴링 방식으로 확인하는 방법뿐 이라는 뜻이다.

 

예시 코드

function students() { 
	for(i=1;i<11;i++) { 
    	console.log(`학생들: ${i}번 문제 푸는중...`) 
        yield; 
    } 
    return 
} 

function teacher() { 
	console.log("선생님: 입실"); 
    const generator = students(); 
    let done;
    while (!done) { 
    	done = generator.next().done; 
        if (!done) { 
        	console.log("선생님: 딴짓") 
        } 
    }; 
    console.log("선생님: 퇴실"); 
} 
    
teacher();

예시 코드 결과

// 출력 결과 
선생님: 입실 
학생들: 1번 문제 푸는중... 
선생님: 딴짓 
학생들: 2번 문제 푸는중... 
선생님: 딴짓 
학생들: 3번 문제 푸는중... 
선생님: 딴짓 
학생들: 4번 문제 푸는중... 
선생님: 딴짓 
학생들: 5번 문제 푸는중... 
선생님: 딴짓 
학생들: 6번 문제 푸는중... 
선생님: 딴짓 
학생들: 7번 문제 푸는중... 
선생님: 딴짓 
학생들: 8번 문제 푸는중... 
선생님: 딴짓 
학생들: 9번 문제 푸는중... 
선생님: 딴짓 
학생들: 10번 문제 푸는중...
선생님: 딴짓 
선생님: 퇴실

출처: https://cotak.tistory.com/136

 

예시처럼 students함수는 콜백이 없기 때문에 students의 동작완료가 필요한 경우에 폴링방식으로 완료 여부를 체크하고있다.

 

비동기와 블럭

 

이 조합이 제일 어렵기 때문인지 예시코드가 없는 글도 꽤 있다.

앞의 동기 논블럭 조합에서 단순히 합친것 처럼 마찬가지로 둘의 개념을 합치면 이해하는데 조금 더 수월할 수 있다.

 

비동기는 콜백이 있다.

블럭은 아무것도 못하고 있어야한다.

 

합쳐보면, 콜백이 있는 작업임에도 불구하고 아무것도 못하고 있는 상황이다.

그런 상황이 오는 경우는 콜백의 결과 값이 다음 로직에 필요한 경우라고 생각했다.

 

예시가 어떤게 있을까 열심히 찾았는데 자바의 future 인터페이스를 알게 되었는데 이를 잘못 코딩하면 딱 비동기x블럭 조합의 상황이 올수있다고 생각했다.

 

사실 나는 future에 대해서 잘 모르지만 비동기를 위해 별도 콜백 작업을 돌리고 값을 얻을 수 있는 개념으로만 알고있다

 

예시 코드

ExecutorService executor = Executors.newCachedThreadPool();
Future<Double> future = executor.submit(new Callable<double>() {
  public int call() {
    return doSomeLongComputation();// 시간이 오래걸리는 Task 완료 후 1을 리턴한다고 가정
  }
});
if(future.get(1,TimeUnit.SECONDS) == 1){
	// 완료 후 동작할 어마어마한 작업들
}

출처 : https://velog.io/@ehdrms2034/Java-8-%EC%95%88%EC%A0%95%EC%A0%81-%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-Completable-Future

 

이게 사실 동작하는 코드인지는 구현을 한게 아니어서 확신할 순 없지만 이해하는데는 문제 없어 보인다.

 

콜백이 있으면서 블럭이 되기위해선, 이 후 작업들이 콜백의 결과를 조건으로 실행되는 작업이어야 한다고 생각했다. 때문에 예시 코드처럼 if나 while의 조건에 콜백 결과가 필요한 경우 비동기x블럭의 상황이라고 생각한다.

 

 

728x90

'그 외' 카테고리의 다른 글

HTTPS 동작 과정  (0) 2022.02.24
[알고리즘] 안정 정렬 (Stable Sort)  (0) 2021.10.11
HTTP 스펙과 버전  (0) 2021.10.09