From fd6853b53442b96ce02d36f5f60ed78eceb94755 Mon Sep 17 00:00:00 2001 From: psh1126 Date: Sat, 24 Aug 2024 23:53:54 +0900 Subject: [PATCH] =?UTF-8?q?Docs:=206=EC=9E=A5=20=EB=B0=95=EC=8A=B9?= =?UTF-8?q?=ED=9B=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\353\260\225\354\212\271\355\233\210.md" | 194 ++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 "6\354\236\245/\353\260\225\354\212\271\355\233\210.md" diff --git "a/6\354\236\245/\353\260\225\354\212\271\355\233\210.md" "b/6\354\236\245/\353\260\225\354\212\271\355\233\210.md" new file mode 100644 index 0000000..966cd4c --- /dev/null +++ "b/6\354\236\245/\353\260\225\354\212\271\355\233\210.md" @@ -0,0 +1,194 @@ +## 들어가며 + +> 동시성(concurrency)과 병렬성(parallelism)을 혼동하지 말자. + +- 둘 이상의 코드 조각이 실행될 때 +- 동시성 + + 동시에 실행 중인 것'처럼' 행동하는 것 + + 실행 중에 코드의 다른 부분으로 실행을 전환할 수 있는 환경에서 코드를 구동해야 한다. + + fiber, thread, process 등을 사용한다. + + fiber : thread보다 더 가벼운 실행 흐름을 만드는 도구. 운영 체제의 스케줄러를 사용하지 않아서 사용자 수준 thread라고 부른다. +- 병렬성 + + 실제로 동시에 실행되는 것 + + 두 가지 일을 동시에 할 수 있는 하드웨어가 필요하다. + + GPU 하나의 여러 코어, 컴퓨터 한 대의 여러 CPU, 또는 네트워크로 연결된 여러 대의 컴퓨터 등 + +
+ +### 나의 생각 + +작가는 정확했다. 나, 동시성과 병렬성의 차이를 몰랐다. + +
+ +## Topic33 : 시간적 결합 깨트리기 + +> 시간적 결합은 당면한 문제 해결에 꼭 필요하지 않은 일 처리 순서를 코드가 강제할 때 생긴다. + +- 프로그래밍을 할 때에는 보통 직선적 사고를 하기 마련이다. '이것을 하고, 그런 다음에 저것을 하고.' 하지만 이런 사고방식은 시간적 결합을 만들어낸다. +- 시간이나 순서에 의존하는 시간적 결합을 끊는 방법을 생각해야 한다. + +
+ +### 동시성 찾기 + +> 작업 흐름을 모델화하고 분석하라. + +- 동시에 일어나도 되는 게 뭐고, 반드시 순서대로 일어나야 하는 게 뭔지 찾자. +- 활동 다이어그램(activity diagram) 같은 표기법을 사용해 작업 흐름을 기록해보자. + +![image](https://github.com/user-attachments/assets/91904b09-8f8b-4085-8973-ad61dde7f5ed) + +- 활동 다이어그램을 사용하면 동시에 수행할 수 있는데도 아직 동시에 하고 있지 않은 활동들을 찾아내서 병렬성을 극대화할 수 있다. + +
+ +### 동시 작업의 기회 + +- 활동 다이어그램은 동시에 작업할 수 있는 부분들을 보여준다. +- 하지만 동시에 하는 것이 좋은 것인지는 알려주지 않는다. +- 그래서 최적의 생산성을 위해서는 설계가 필요하다. +- 어떤 작업이 오래 걸리니 작업을 걸어두고 다른 작업들을 그때 한다던지. +- 우리 코드가 아닌 곳에서 시간이 걸리는 활동을 찾아 활용하자. + +
+ +### 병렬 작업의 기회 + +- 동시성은 소프트웨어, 병렬성은 하드웨어 동작 방식이다. +- 전체 소요 시간을 단축하기 위해서 가장 이상적인 것은 비교적 독립적인 부분 작업으로 나눠 병렬 처리 하고 결과를 합치는 것이다. + +
+ +### 나의 생각 + +- 동기적 처리에서 다른 일의 결과를 기다리는 것 역시 하나의 결합이라는 사실이 어떻게 보면 당연하지만 꽤나 색다르게 다가왔다. 이 시간적 결합을 끊기 위해 비동기적 처리를 더 우아하게 사용할 필요가 있겠다고 생각했다. +- 아직 한 번에 여러 태스크를 복잡하게 처리해야 할 일을 마주하지 못해서인지 활동 다이어그램을 사용해본 적도 없고, 동시성과 병렬성을 구분할 일도 없었던 것 같다. +- 활동 다이어그램을 보며 생각했던 건 `Promise.all()` 같다는 것이었다. `Promise.all()`는 여러 개의 프로미스를 동시에 처리하고 결과를 합쳐주는 메서드이다. 활동 다이어그램에서 이전 작업들을 모두 마치고 하나의 작업을 다시 시작하는 경우처럼, 이전 작업들을 모두 마친 상황에서 다음을 진행하고, 만약 한 선행 작업이 정상이 아니라면 다음 작업을 진행하지 않는다던지 하는 것이 비슷한 것 같다. + +
+ +## Topic34 : 공유 상태는 틀린 상태 + +> 둘 이상의 코드 뭉치가 하나의 변경 가능한 데이터를 참조하고 있다면 공유 상태가 존재하는 것이다. + +
+ +### 비원자적 갱신 + +- 프로세스의 처리가 길어질 때 다른 프로세스가 공유 상태를 바라봤을 때 변경이 없기 때문에 다른 프로세스 역시 진행될 수 있다. +- 프로세스의 여러 단계가 한 번에 얽혀 갱신이 늦어지는 것을 비원자적 갱신이라고 한다. 이 프로세스가 진행되는동안 실제 값이 바뀔 수 있다. +- 가장 큰 문제는 어느 프로세스도 자신이 보는 메모리가 일관되어 있음을 보장할 수 없다는 것 + +
+ +### 세마포어 및 다른 상호 배제 방법 + +- 세마포어(semaphore) : 단순히 한 번에 한 사람만이 가질 수 있는 무언가 +- 세마포어는 공유 상태를 사용할 때 발생하는 문제를 해결하기 위한 방법 중 하나이다. +- 프로세스가 공유 상태를 사용하기 위한 권한이며, 이 권한은 유일하기 때문에 한 프로세스가 세마포어를 점유하고 있다면, 다른 프로세스는 공유 상태를 사용하기 위해 세마포어를 점유한 프로세스를 '기다려야 한다.' +- 또한 치명적인 단점은 **모든 사람이 빠짐없이 세마포어를 사용해야만 제대로 동작해야 한다는 것**이다. 만약 누군가 세마포어를 사용하지 않으면 다시 혼돈에 빠진다. + +
+ +### 리소스를 트랜잭션으로 관리하기 + +- 설계가 미흡한 이유는 공유 상태를 보호할 책임을 사용하는 프로세스에게 전가하기 때문이다. +- 제어를 중앙으로 집중시키고 프로세스의 공유 상태 사용을 트랜잭션으로 한 플로우로 관리할 수 있게 한다. +- 하지만 이 역시 동시에 요청될 수 있으므로 세마포어로 관리해야 한다. +- 세마포어를 활용하고, 세마포어의 교착상태를 피하기 위해 여러 성공/실패 분기처리를 추가한다. +- 그러나 이는 비즈니스 로직에 여러 불순물을 끼게 하여 가독성으로부터 멀어지게 한다. + +
+ +### 그럼 어쩌란 말이죠? + +> 리소스를 공유하는 환경에서 동시성은 어렵다. + +
+ + +### 나의 생각 + +- 이번 토픽에서는 공유 상태의 사용과 성공-실패의 상황을 `손님-종업원-진열장`에 비유했다. '이거.. 꽤 괜찮은 비유 같은데?'라는 생각이 들었다. +- 하지만 그 뒤부터는 난해했다. 앞에서는 '비원자적'인 큰 프로세스에서부터 공유 상태의 갱신이 늦어지며 문제가 발생했는데, 그래서 점유 권한을 위해 '세마포어'라는 개념이 등장했다가, 이건 모두가 합의해야 되고, 동기적인 문제가 있다며 '트랜잭션'으로 관리하자고 했다. 그런데 '트랜잭션'도 결국 큰 하나의 일련의 작업이므로 여러 스레드에서 동시에 호출될 수 있다는 '비원자적'인 성격을 가지기 때문에 문제가 있어 '세마포어'로 관리해야 한다고 했다. 그리고 정상 동작을 위해 여러 실패 방어처리를 하는데, 이것도 별로라고 했다. +- 결론은 리소스를 공유하면서 동시성을 지키는 건 어렵다는 교훈만 남겼다. +- 다음 토픽에서 명쾌한 해답을 제안하며 극적인 반전을 주기 위한, 답답함을 쌓는 빌드업이었다면 훌륭했다. 충분히 난해했고 답답했다. + +
+ +## Topic35 : 액터와 프로세스 + +> 공유 상태가 문제라면 공유 상태를 없애면 되지 않는가? + +
+ +### 액터 모델 + +- 프로세스들이 독립적으로 수행된다. +- 자신만의 비공개 지역 상태를 가진 독립적인 가상 처리 장치(virtual processor)이다. +- 그래서 서로 데이터를 공유하지 않는다. +- 채널을 통해 잘 정의된 단순한 의미론을 사용하여 의사소통한다. + +
+ +### 액터 모델에서 찾아볼 수 없는 것 + +- 액터를 관리하는 것 +- 시스템이 저장하는 상태 +- 메시지의 양방향성 +- 액터의 멀티태스킹 + +
+ +이를 통해 액터들은 아무것도 공유하지 않으면서 비동기적으로 동시에 실행된다. + +
+ +### 나의 생각 + +- 이번 토픽도 저번 토픽에 이어 `손님-종업원-진열장` 비유의 연장이었고, 각각을 액터로 대응시켰다. 나는 이 비유가 너무 적절한 것 같아 마음에 든다. +- 그리고 그동안 루비와 엘릭서로 떡칠이 되어 있던 예시코드를 벗어나 처음으로 자바스크립트 언어로 예시를 들어준 것도 마음에 들었다. (물론 일반적으로 쓰는 코드 구조가 아니라 알아듣기 힘든 건 매한가지였다.) +- 액터 모델이 다양한 장점을 가지는 구조라는 사실은 잘 알겠다. 하지만 저수준의 프로그래밍이 아니라 어느 정도 갖춰진 라이브러리와 언어 위에서 프론트엔드 개발을 하고 있는 지금 나의 상황에서는 크게 와닿지는 않는 구조였다. 어느 정도 언어, 라이브러리 내부적으로 하드웨어 리소스를 관리하는 구조는 숨어있을 수도 있겠다. + +
+ +## Topic36 : 칠판 + +### 칠판 모델 + +- 여러 형사들이 사건을 해결하기 위해 하나의 칠판을 두고 모인 것을 상상해보자. +- 하나의 큰 보드 위에 누군가는 단서들을 올리고, 누군가는 이 단서들끼리 엮고, 또 누군가는 이를 내리거나 새로운 요소들을 추가한다. +- 이 과정에서 이들은 서로 알 필요가 없다. 누가 언제 개입하고 언제 빠져나가는지, 어떤 능력을 가지고 있는지 알 필요가 없다. +- 이 과정은 문제가 해결될 때까지 계속된다. + +
+ +### 칠판 모델의 가치 + +- 일종의 '자유방임주의'적 동시성 +- 사람들이 서서히 결론에 도달하도록 돕는다. + +
+ +### 칠판 모델의 동작 + +- 객체 저장소와 똑똑한 게시-구독 중개자(broker)를 합한 것처럼 동작하는 시스템 +- 어떤 사실이 칠판에 올라가면 적절한 규칙이 발동한다. +- 어떤 규칙에서 나온 것이든 그 결과를 다시 칠판에 올려서 다른 규칙들이 발동되도록 하면 된다. + +
+ +### 나의 생각 + +- 나는 하나의 단서가 올라갔을 때 이와 관련된 다른 규칙들이 발동된다는 점에서 스도쿠가 생각났다. 스도쿠는 하나의 숫자가 채워질 때마다 다른 숫자들의 후보군이 줄어들어야 한다. 그래서 숫자를 채우면 해당 숫자와 연관된 가로, 세로, 대각선, 가능한 케이스들을 전반적으로 다시 검토한다. +- 액터 방식을 다뤘던 이전 토픽에 비하면 비교적 현실 세계와 가까웠던 이유인지 그나마 조금 더 피부에 와닿는 방식인 것 같다고 느꼈다. 하지만 실제 개발에 접목하기 위해서는 이전 장에서 다룬 여러 반응형 프로그래밍 모델들을 더 참고하는 게 좋겠다. + +
+ +## 총평 + +- 유난히 한 토픽 한 토픽을 곱씹으면서 봤던 장인 것 같다. +- 각 토픽마다 생각을 남기는 게 더 효율적이라고 느꼈다. 더 많은 내용을 한 흐름으로 풀어내기 좋았다. +- 난해함의 연속이었던 `Topic34 : 공유상태는 틀린 상태`를 지나, `Topic35 : 액터와 프로세스`에서 대단한 통찰을 얻을 줄 알았는데, 생각보다 그렇지만은 않아서 찝찝함만 남았다. 내가 부족한 탓일까. +- 칠판 모델은 비교적 잘 와닿았다. 하지만 '이런 게 있구나'로 그쳤고, 이를 실제로 활용하는 것은 이전 장으로 다시 돌아가야 할 것 같다.