Page History
...
| Code Block | ||||||||
|---|---|---|---|---|---|---|---|---|
| ||||||||
var tasks = new List<Task>();
tasks.Add(actorA.Ask("request", TimeSpan.FromSeconds(1)));
tasks.Add(actorB.Ask("another request", TimeSpan.FromSeconds(5)));
Task.WhenAll(tasks).PipeTo(actorC, Self); |
...
액터의 리소스사용
...
- 요구사항대비 자원이 증가하는 경유
- 자원이 증가하여 복잡도가 증가하는 경우
Dispatcher는 성능과 관련한 액터로, 멀티스레드개념을 어느정도 단순화하고 옵션화를 했다고 보시면될듯합니다.
이와 관련하여 위 그래프는 아주 중요한 의미를 내포하고 있습니다.
고성능처리를 위해서 개발 복잡도가 증가하고 (심각하게는 고성능처리에 대해 아무것도 할수 없음)
요구사항 증가로인해, 필요한 자원이 계속 증가한다면 그것은 파멸적 시나리오로 연결될것입니다.
분산 개발 환경에서 해결 키 포인트가 멀티스레드 작성이라고 생각하고, 시도 했다면 다행입니다.
문제는 그것이 분산환경에서 복잡한 연산처리에서도 이것이 해결을위한 키포인트로 정의 내리는 굳은 믿음에 있으며
대부분 인메모리(네트워크가없는) 상황에서도 스레드를 직접 작성하여 처리능력을 올리는것은 큰 도움이 되지 않습니다.
이것은 개발복잡도 증가요인으로 해당이 되는 사항입니다.
이미 동시성 처리를 위해 멀티스레드를 직접 작성하지않는 여러가지 모델들이 등장했으며
액터모델은 그중에 하나일뿐입니다.
- 사용 자원증가에 따른 최대 한계측정
스레드의 비용
| 항목 | 비용 | 상세 |
|---|---|---|
| 커널메모리 | 약 1KB | 스레드 데이터와 속성들을 저장합니다. 이 데이터들은 페이징 될 수 없습니다. |
| 스택영역 | 512KB(일반 스레드), 8MB(OS X 메인 스레드), 1MB(iOS 메인 스레드) | 일반 스레드의 스택 영역은 최소 16KB이고, 4KB의 배수여야 합니다. 해당 메모리는 스레드가 생성될 때 할당되지만, 실제 사용되기 전까지 페이지가 생성되지는 않습니다. |
| 생성 시간 | 약 90ms | 스레드 생성 요청부터 스레드 루틴이 시작될 때 까지의 시간 |
스레드는 스택영역에 생성되기때문에 생성만 되어도 기본적으로 큰 메모리를 차지하게됩니다.
채널처리라는 도메인처리를 단일장비에서 1000개가 필요하다고 가정해봅시다.
- 1000 * 1mb = 약 1gb
채널하나당 스레드로 할당하게되면 아무런 일을 하지 않고도 1gb의 메모리를 차지하게 됩니다.
물론 스레드풀을 이용하여 스레드를 더 적게 사용할수 있도록 설계할수도 있습니다. 하지만 이것은 도메인 프로그래밍이 아니라 시스템 프로그래밍이 되게 됩니다.
도메인 로직속에 시스템 프로그래밍이 결정적으로 함께 있어야함을 의미하며 멀티스레딩 프로그래밍이란 다루기 어려운 시스템 프로그래밍을 깊이 있게 학습해야합니다.
반면 액터의 경우 스택영역이 아닌 힙영역에 생성되며 200만개의 액터가 사용하는 메모리는 고작 1GB에 불가합니다.
물론 이것이 200만개의 액터가 모두 동시에 진행할수 있다란것을 보장하는것은 아닙니다.
액터를 실행하는 스케줄러는 Dispacher에서 튜닝을 할수 있으며 스레드수를 조절할수 있습니다.
스레드 사용전략을 도메인 모델을 가지고 있는 액터모델과 완벽하게 분리할수 있음을 의미하며 실행레벨에 정의할수도 있지만
설정화로 완벽하게 분리하여 빌드없이 튜닝옵션으로 실행단계에 결정할수도 있습니다. (어떠한 특수목적으로,병렬처리를 위해 스레드를 극단적으로 이해하고 사용해야되는 케이스도 분명 있습니다.)
