devEvan
852
2019-09-19 07:07:23
6
1000

동기(Synchronous)는 정확히 무엇을 의미하는걸까?


안녕하세요. 이번에는 동기(Synchronous)에 대한 포스팅을 작성해보았습니다 :)


사실 이 동기라는 용어가 상황에 따라 의미가 달라지기도 하고 일상에서 사용하는 용법과도 차이가 있기 때문에 많은 분들이 혼란스러워 하는 개념 중 하나라고 생각해요.


그래서 이번에는 동기라는 단어가 가지는 의미와 실제로 이 개념들이 사용되는 예시들을 한번 소개해볼까합니다🙂

https://evan-moon.github.io/2019/09/19/sync-async-blocking-non-blocking/

4
7
  • 댓글 6

  • satis
    2k
    2019-09-19 17:43:00
    구독 잘 하고 있습니다 ^^
    0
  • 하마
    6k
    2019-09-19 18:41:22 작성 2019-09-19 18:47:26 수정됨

    먼가 좀 오해가 있어 보이네요.

    예를들어 

    예제1)
    A 라는 브라우저에서 B 서버에 무엇인가 요청하고 기다림.  (블로킹 콜)
    B 서버는 C 미들웨어에 넘기고 바로 리턴받아서 A에게 바로 리턴해줌. (논블로킹 콜) 
    A 는 요청 성공 메세지 (결과 메세지가 아님) 를 받음.
     
    A는 요청 결과 메세지를 받기 전까지 다른 행동을 함~~

    B서버는 시간이 흐른 뒤, C 미들웨어에게 던졌던 결과를 D 허브를 통해서 전달받음.
    B서버는 A 에게 결과를 PUSH함.
    A는 결과를 받아서 그것이 OK라면 F 서버로 요청. 

    이 경우 업계에서는 "비동기" 방식 처리 라고 말합니다.
    A 는 자신의 첫번째 요청에 대한 결과를 계속 기다리지 않고 다른 행위를 하기 때문이죠.

    하지만 위 글의 논리대로라면 이 방식은 "동기" 식이 됩니다.
    결과를 받은 후에야 그 결과에 맞는 행위를 시작 하니까요.

    결과를 받지 않고, 그 결과에 따른 행위를 시작 하는 것은 대게 없습니다.

    예제2)
    IOCP 같은 대표적인 asynchronous  i/o 시스템이 있는데 (proactor 패턴의 부류) 
    read / write 를 위임시키고, 다른 일을 처리하다가 
    read/write 결과가 compleation 되는 시점에는 그 "결과" 를 가지고서 이어서 처리하게 됩니다.
    즉 해당 관심사에 대해서는 순차적입니다.

    예제3)
    Future 패턴에서도 완료됬는지 계속 물어보는 방식과
    완료되면 연결된 함수를 호출 하는 방식이 든간에..

    둘 다 비동기 방식입니다.
    전자는 중간 중간 멈추고 확인 할 뿐이고
    후자는 확인하지 않고 다른 쓰레드에서 호출 할 뿐.

    어쨋건 둘 다 결과에 의존하는 행위를 결국 하게 되겠지요. 역시 순차적입니다.

    따라서 
    "현재 작업의 응답과 다음 작업의 요청" " 여기에서 오해가 시작되어..  
    "동기라는 것은 작업들이 순차적인 흐름을 가지고 있다는 것"  로 발전되어...

    동기,비동기 구분의 근거로 모든 예가 작동하고 있는데. 좀 무리가 있다라고 판단됩니다.


    p.s

    비동기/동기/블록/논블록을 조합해서 명확히 구분하려고하는
    모든 시도는 결국 실패하게 된다고 생각합니다.
    그냥 대략 이런 경우에는 이렇게 말하더라~~ 정도로 구분하면 족한 개념들일뿐.

    0
  • devEvan
    852
    2019-09-19 22:48:02

    @satis 감사합니다! :)

    0
  • devEvan
    852
    2019-09-19 23:59:40

    @하마


    넵 옳으신 말씀입니다. 우선 말씀해주신 것들에 대한 제 생각을 말씀 드려보자면


    예제1)

    이 경우 클라이언트와 서버의 통신만 보면 동기, 서버와 미들웨어의 통신은 비동기, 이후 모든 작업이 완료되어 서버가 클라이언트에 push 해주는 방식은 비동기 등 하나의 워크 플로우에도 다양한 방법들이 포함되어 있습니다. 이런 현상은 이 워크 플로우에만 국한되는 것이 아니라 다른 작업들도 마찬가지지요.

    그렇기 때문에 결국은 어디까지 묶어서 생각하냐에 이 워크 플로우가 동기냐, 비동기냐는 달라질 수 있다는 생각이 듭니다. 물론 말씀해주신 예의 전체적인 워크 플로우는 비동기식입니다 :)


    예제2)

    우선 저는 iocp를 사용해본 적이 없기 때문에 이 부분은 양해를 부탁드립니다. 제가 알고 있는 proactor패턴은 비동기 작업이 완료되면 이벤트 핸들링하는 패턴으로 알고있는데, 어떠한 작업이 끝나면 순차적으로 이벤트 핸들러가 호출되므로 마찬가지로 이 관계만 보면 동기라고 해석될수도 있다고 생각합니다.

    그러나 이 전체 플로우가 비동기라고 불리는 이유는 상위 프로세스가 proactor 패턴을 사용한 프로세스에게 작업을 지시한 이후, 처리되는 작업들의 순서가 보장되지 않기 때문이기도 하고 상위 프로세스가 해당 작업들의 완료 여부를 신경쓰고 있지 않기 때문이기도 합니다. 작업이 완료된 후의 처리는 미리 등록해놓은 이벤트 핸들러가 처리하는 것이지 작업을 지시한 상위 프로세스가 처리하는 것이 아니니까요.


    예제3)

    Future 패턴의 isDone, isComplete 등을 사용하는 방식이 동기냐 비동기냐는 개발자들 사이에서도 의견이 갈리는 것으로 알고 있습니다. 저는 개인적으로 작업을 지시한 상위 프로세스가 하위 프로세스의 작업 완료 여부를 신경써야한다는 점에서 이 과정은 동기 방식이라고 생각합니다. 물론 별도의 Executor를 사용하여 처리하는 방법은 비동기이구요.



    그리고 말씀하신 부분처럼 동기, 비동기라는 것이 명확한 이론이 아니고 추상적인 개념에 가까운 것이다보니까 어떤 특정 예제를 가져와서 “이게 동기고 이게 비동기다”라고 하는 것에는 무리가 있다고 생각합니다.

    그러나 이 개념에 대해서 잘 모르고 계신 분들께 설명할 때는 프로세스, 클럭, 이벤트 등의 개념을 가져와서 설명하는 것보다 익숙한 코드를 예시로 설명하는 것이 더 이해가 잘될 것이라고 생각했습니다. 사실 제가 동기&논블럭의 예제로 사용한 제너레이터 역시 비동기 프로그래밍의 요소 중 하나이기 때문에 엄밀히 따지자면 맞는 예제는 아니지요.


    하마님께서 남겨주신 피드백을 하나하나 읽어보면서 제가 포스팅을 작성하면서 “이 정도는 괜찮겠지”하고 넘어갔던 부분들을 예리하게 짚어주셔서 놀랐습니다. 반성하게 되네요 ㅜㅜ

    소중한 시간 내어 긴 글로 이렇게 자세하게 피드백주신 분이 처음이라 저도 그에 대한 제 생각을 최대한 적는 것이 예의라고 생각되어 한번 적어보았습니다. 피드백 감사합니다!

    0
  • Frudy
    3k
    2019-09-20 07:17:21
    와드남겨놓을게요.
    글 감사해요.
    0
  • 하마
    6k
    2019-09-20 09:24:29 작성 2019-09-20 22:08:45 수정됨

    @devEvan

    글 잘 읽었습니다.
    댓글로 써 주신 글에 대해 오류도 짚어보고 제 생각도 말해 보겠습니다.

    위 댓글에서는 동기/비동기의 주요 요소로  "주 프로세스의 역할" 을 강조하셨습니다. 
    그리고 콜백/이벤트 핸들러의 존재를 강조하셨습니다. 

    근데 제 생각으론 이벤트를 받아서 처리하든, 짬짬히 기다리든... 이런 것은 하나의 소프트웨어 "트릭" 에 불과하다고 생각됩니다. 물론 그것을 동기/비동기를 구분하는 기준으로 삼는 것 자체가 무조건 틀린것이다라고 생각하지는 않습니다. 중요한건 일관성이니까요. 예를 다시 보겠습니다. 


    1)

    패스

    2)

    Proactor 패턴의 주요관삼사는 " 이벤트 핸들링"이 아닙니다.  그것은 단지 하나의 "트릭"에 지나지 않으며 
    해야 할 일(Job)에 대한 제어권을 수동적으로 받아드리냐, 능동적으로 처리하냐의 차이입니다.
    예를들어 우체국에 짐을 마구 던저버리는 행위는 proactor,  우체국에서 자리가 났다고 알려주면 그 때서야 짐을 들고 가는 것을 reactor라고 볼 수 있는데, 초고속io의 대명사인 Windows IOCP 등 여러 비동기 입출력 Implementation에서, Write를 던져 놓고,  "주 프로세스" 는 GetQueuedCompletionStatus 를 통해 블록되어 기다립니다. 
    우체국에 짐을 던져놨는데, 우체국이 다 보냈어요~~ 라고 알림을 주면 그때 "주 프로세스" 는 GetQueuedCompletionStatus 에서 리턴되어, 잘 보내졌는지 or 먼가를 받았는지 확인하고, 받은 결과에 대해서는 Worker 쓰레드들에게 넘기고 다시 "주 프로세스" 는 대기하게 됩니다. 

    자 여기서 그럼 "주 프로세스" 가 기다리니깐 동기 라고 한다면 , 그냥 쓰레드 하나 더 만들어서 거기서 
    "GetQueuedCompletionStatus 를 기다리면" 비동기가 될 까요?? 그죠 이건 그냥 레이어링을 얼만큼 하느냐에 따라서 달라지는 문제라고 볼 수 있습니다.
     

    3)

    Future 패턴도 마찬가지 입니다. isDone을 쓰던, 별도의 Executor를 쓰던 이것은 그냥 트릭에 불과 합니다.
    큰 그림에서는 결국 다른 쓰레드or 프로세스 or 네트워크 넘어 누군가에서 처리하고 있는 "비동기" 상태로 볼 수 있기 때문입니다. 만약 isDone이 주 프로세스가 짬짬히 확인을 하는 거라서 동기라면 
    쓰레드 하나 더 만들어서 그 녀석(a) 이 짬짬히 확인하게 만들고,  또 다른 쓰레드(b)에게 이벤트 핸들러를 만들어서 a에 등록시켜 놓으면 "동기"가 아닌걸까요?? 


    다시 말하지만 그런 명제로  동기/비동기를 판단을 하는게 "틀렸다"라고 말하는건 아닙니다만.
    (왜냐면 자신만의 "일관적인" 시각이 있으면, 개별 기술을 받아드리고 판단하는데 명쾌해지니까) 
    누구에게나 동기/비동기는 이렇게 구분한다라고 말하여지기에는 무리가 있다고 생각합니다.

    이 글을 읽는 분들도 여러 사람들의 생각을 종합해서 본인만의 일관적인 구분점을 갖게 되길 바랍니다. 아~ 구분점이 명확치 않다 라고 규정하고 감만 잡는것도 좋습니다.  ^^

    감사합니다.




    1
  • 로그인을 하시면 댓글을 등록할 수 있습니다.