os

동기 vs 비동기, Blocking vs Non Blocking (feat. Coroutine)

쭈돌s 2022. 10. 5. 01:12

회사에서 이메일 프로젝트를 하던중 비동기적으로 이메일을 발송을 해야한다는 요구사항이 있었다.

처음 이메일 서비스를 만들어 볼 뿐더러 동기와 비동기에 대한 개념이 온전치 못하였어서 이번업무를 하면서 

공부를 해보게 되었다.

 

sync 동기 : 순차적으로 프로세스가 실행되고 순차적으로 프로세스가 종료됨을 뜻함

ex) 일반적으로 코드들을 작성하면 동기적으로 진행이된다

async 비동기 : 비순차적으로 프로세스가 실행 및 종료가 됨을 뜻함.

 

Blocking : 메인 worker 의 제어권을 block 하여 다른 worker 에게 준다.

Non Blocking : 메인 worker 의 제어권을 뺏지 않고 다른 worker 도 일하게 해준다.

 

이렇게 위의 2가지 x 2가지 옵션으로 총 4가지의 옵션들이 만들어지게 된다.

 

(비동기에 대한 예시는 코틀린 코루틴으로 들도록 하겠다)

참조 : 코루틴은 쓰레드를 다루는 것이 아니라 쓰레드보다 더 작은 object 라는 작업을 이용한다. 

이때 쓰레드와의 차이점은 크기 뿐만 아니라 이용하는 메모리 영역도 다르다.

쓰레드는 스택메모리를 이용한다 그래서 프로세스간의 메모리 공유가 되지 않는다.

하지만 코루틴에서 사용하는 object 작업은 큐메모리를 이용하기 때문에 프로세스간의 이동(및 연산등)도 가능하다.

 

1. Sync & Blocking

메인 worker를 중단시키면서, 순차적으로 worker에게 일시키는 것

ex) 1번의 메서드 안에 2번의 메서드가 있을 때 1번 메서드가 동작중 2번을 실행하게 될 때 1번을 동작하던

worker 가 Blocking되어 멈추고 2번메서드가 끝날 때 까지 Synchronous 하게 기다린 후 실행한다.

이것은 일반적인 동기적 방식이다.

fun main(args: Array<String>){
    firstWrite()
    secondWrite()
}

fun firstWrite(){
    println("number1")
}

fun secondWrite(){
    println("number2")
}

 

2. Async & Blocking

메인 worker를 중단시키면서, 비순차적으로 worker에게 일시키는 것 (여기서 비순차적이라함은 함은 동시에 실행될 수 있도록 하는 것도 포함한다)

ex) 데이터 전송을 위한 링크의 비용이 비쌌던 시절 여러 요청을 한꺼번에 받아서 날리는 경우가 있었는데 이방식을 Multiplex 기법이라 한다. 이 때 동기적으로 request 를 날렸다고 한다. 대표적인 예로 Hub 라고 한다. 이방식의 장점은 요청에 대한 비용을 줄일 수 있다. 

https://m.blog.naver.com/gkenq/220693036639

 

fun main(args: Array<String>) = run {
    runBlocking {

        launch {
            firstWrite()
        }
        launch {
            secondWrite()

        }
    }
    println("end")
}

suspend fun firstWrite() {
    delay(3000L)
    println("number1")
}

suspend fun secondWrite() {
    delay(3000L)
    println("number2")
}
결과
number1
number2
end

(기다리다가 동시에 모두 출력됨)

 

3. Sync & Non Blocking

메인 worker를 중단시키지 않으면서, 순차적으로 worker들에게 일시키는 것

 

fun main(args: Array<String>) = runBlocking {

    launch {
        firstWrite()
        secondWrite()
    }
    println("end")
}

suspend fun firstWrite() {
    delay(3000L)
    println("number1")
}

suspend fun secondWrite() {
    delay(3000L)
    println("number2")
}
결과
end     (가장먼저 출력)
number1 (3초뒤 출력)
number2	(이어서 3초뒤 출력)

 

4. Async & Non Blocking

 

메인 worker를 중단시키지 않으면서, 비순차적으로 worker에게 일시키는 것 (여기서 비순차적이라함은 함은 동시에 실행될 수 있도록 하는 것도 포함한다)

fun main(args: Array<String>) = runBlocking {
    launch {
        firstWrite()
    }
    launch {
        secondWrite()

    }
    println("end")
}

suspend fun firstWrite() {
    delay(3000L)
    println("number1")
}

suspend fun secondWrite() {
    delay(3000L)
    println("number2")
}

 

 

<결과>
end
number1 (거의 동시출력)
number2 (거의 동시출력)

 

 

 

3,4 번처럼 Non Blocking 전략을 쓰는 방법의 대표적인 예로 Email Sending 을 들 수 있다.