언제“수만”의 스레드가 필요할까요?


31

Erlang, Go 및 Rust는 모두 저렴한 "스레드"/ 코 루틴으로 동시 프로그래밍을 지원한다고 주장합니다. 이동 자주 묻는 질문 상태 :

동일한 주소 공간에 수십만 개의 고 루틴을 만드는 것이 실용적입니다.

녹 자습서는 말합니다 :

작업은 기존 스레드보다 훨씬 저렴하기 때문에 Rust는 일반적인 32 비트 시스템에서 수십만 개의 동시 작업을 만들 수 있습니다.

Erlang의 문서 는 다음과 같이 말합니다.

수십만 또는 수백만 개의 프로세스로 Erlang 시스템을 지원하기 위해 기본 초기 힙 크기 233 워드는 상당히 보수적입니다.

내 질문 : 어떤 종류의 응용 프로그램에 너무 많은 동시 실행 스레드가 필요합니까? 가장 바쁜 웹 서버 만 수천 명의 동시 방문자를받습니다. 내가 작성한 보스 작업자 / 작업 디스패치 유형 응용 프로그램 스레드 / 프로세스 수가 물리적 코어 수보다 훨씬 클 때 적중률이 감소합니다. 숫자 응용 프로그램에는 의미가 있다고 생각하지만 실제로 대부분의 사람들은 이러한 차세대 언어가 아닌 Fortran / C / C ++로 작성된 타사 라이브러리에 병렬 처리를 위임합니다.


5
혼란의 근원은 다음과 같습니다.이 마이크로 스레드 / 작업 / 등은 주로 말하는 OS 스레드 / 프로세스를 대체하기위한 것이 아니며 쉽게 병렬화 할 수있는 큰 숫자 덩어리를 나누는 데 사용되지 않습니다 몇 개의 코어 사이 (정확히 말했듯이, 그 목적을 위해 4 개의 코어에 100k 스레드가있는 지점은 없습니다).
us2012

1
그렇다면 그들은 무엇을 의미합니까? 어쩌면 나는 순진하지만 코 루틴 등을 도입하여 단일 스레드 실행 프로그램을 단순화 한 상황에 처한 적이 없었습니다. 그리고 프로세스에서 "낮은"수준의 동시성을 달성 할 수있었습니다. Linux에서는 땀을 흘리지 않고 수백 또는 수천을 시작할 수 있습니다.
user39019 2019

많은 작업이 실제로 작동하는 것은 의미가 없습니다. 그렇다고 대부분의 일이 발생하기를 기다리는 것만으로 대부분 차단 된 작업을 수행 할 수 없다는 의미는 아닙니다.
Loren Pechtel

5
작업 기반 비동기 및 스레드 기반 비동기의 개념은 사용자 코드가 해당 작업을 수행하는 작업자관리하는 대신 발생해야하는 작업에 집중 해야한다는 것 입니다. 실을 당신이 고용 한 노동자로 생각하십시오. 직원을 고용하는 것은 비용이 많이 들며, 가능하면 100 %의 시간 동안 가능한 많은 작업을 수행하기를 원합니다. 다수의 시스템은 수백 또는 수천 개의 보류중인 작업을 특징으로 할 수 있지만 수백 또는 수천 명의 작업자가 필요하지 않습니다.
Eric Lippert

@EricLippert의 의견에 이어 수십만 개의 작업이 존재하는 몇 가지 상황이 있습니다. 예 # 1 : 이미지 처리와 같은 데이터 병렬 작업의 분해 예 # 2 : 수십만 개의 클라이언트를 지원하는 서버. 각 서버는 언제든지 명령을 실행할 수 있습니다. 각 작업에는 자체 "경량 실행 컨텍스트"가 필요합니다. 현재 상태 (통신 프로토콜) 및 현재 실행중인 명령을 기억하는 기능은 거의 없습니다. 각각 얕은 호출 스택을 가지고있는 한 경량이 가능합니다.
rwong

답변:


19

하나의 유스 케이스-웹 소켓 :
웹 소켓은 단순한 요청에 비해 오래 지속되므로 바쁜 서버에서는 많은 웹 소켓이 시간이 지남에 따라 누적됩니다. 마이크로 스레드는 훌륭한 개념 모델링과 비교적 쉬운 구현을 제공합니다.

보다 일반적으로, 많은 자율적 인 단위가 특정 이벤트가 발생하기를 기다리는 경우가 좋은 사용 사례가되어야합니다.


15

Erlang이 원래 의도 한 것, 통신 관리를 위해 고안된 것을 생각하면 도움이 될 수 있습니다. 라우팅, 스위칭, 센서 수집 / 집계 등과 같은 활동

이것을 웹 세계로 가져 오십시오 – 트위터 와 같은 시스템을 고려하십시오 . 시스템은 아마도 웹 페이지를 생성 할 때 마이크로 스레드를 사용하지 않을 수도 있지만 트윗의 수집 / 캐싱 / 배포에 사용할 수 있습니다.

이 기사 는 추가 도움이 될 수 있습니다.


11

변수를 수정할 수없는 언어에서 상태를 유지하는 간단한 작업에는 별도의 실행 컨텍스트가 필요합니다 (대부분의 사람들은 스레드를 호출하고 Erlang은 프로세스를 호출 함). 기본적으로 모든 것이 노동자입니다.

카운터를 유지하는이 Erlang 함수를 고려하십시오.

counter(Value) ->
    receive                               % Sit idle until a message is received
        increment -> counter(Value + 1);  % Restart with incremented value
        decrement -> counter(Value - 1);  % Restart with decremented value
        speak     ->
            io:fwrite("~B~n", [Value]),
            counter(Value);               % Restart with unaltered value
        _         -> counter(Value)       % Anything else?  Do nothing.
    end.

C ++ 또는 Java와 같은 기존의 OO 언어에서는 개인 클래스 멤버가있는 클래스, 상태를 가져 오거나 변경하는 공용 메소드 및 각 카운터의 인스턴스화 된 오브젝트를 사용하여이를 수행 할 수 있습니다. Erlang은 인스턴스화 된 객체의 개념을 프로세스로 대체하고, 메쏘드의 메시지 개념과 상태 유지는 테일 호출로 새 상태를 구성하는 값으로 함수를 다시 시작합니다. 숨겨진이 모델의 장점 -와 얼랑의 대부분의 존재 이유 - 언어가 자동으로 고도의 안전과 구현하기 매우 쉬운 동시 코드를 만들고, 메시지 큐의 사용을 통해 카운터 값에 대한 액세스를 직렬화한다는 것입니다 .

컨텍스트 스위치가 비싸다는 생각에 익숙 할 것입니다. 호스트 OS의 관점에서는 여전히 그렇습니다. Erlang 런타임 자체는 작은 운영 체제로 조정되어 자체 프로세스 간 전환이 빠르고 효율적이며 OS가 수행하는 컨텍스트 전환 수를 최소로 유지합니다. 이러한 이유로 수천 개의 프로세스를 갖는 것은 문제가되지 않으며 권장됩니다.


1
마지막 응용 프로그램은 counter/1소문자 c를 사용해야합니다.;) 나는 그것을 고치려고했지만 StackExchange는 1 문자 편집을 좋아하지 않습니다.
d11wtq 2

4

내 질문 : 어떤 종류의 응용 프로그램에 너무 많은 동시 실행 스레드가 필요합니까?

1) 언어가 "확대"한다는 것은 상황이 복잡해지면 그 언어를 버릴 확률이 적다는 것을 의미합니다. (이를 "전체 제품"개념이라고합니다.) 많은 사람들이 이런 이유로 Nginx 용 Apache를 버리고 있습니다. 스레드 오버 헤드에 의해 부과되는 "하드 한계"에 가까운 곳에 있으면 두려워하고 지나칠 방법에 대해 생각하기 시작합니다. 웹 사이트는 트래픽 양을 예측할 수 없으므로 약간의 시간을 투자하여 확장 성을 만드는 것이 합리적입니다.

2) 시작 당 요청 당 하나의 고 루틴. 내부적으로 고 루틴을 사용해야하는 많은 이유가 있습니다.

  • 100 개의 동시 요청이있는 웹 앱을 고려하지만 각 요청은 100의 백엔드 요청을 생성합니다. 명백한 예는 검색 엔진 애그리 게이터입니다. 그러나 대부분의 앱은 화면의 각 "영역"에 대해 고 루틴을 생성 한 다음 순차적 대신 독립적으로 생성 할 수 있습니다. 예를 들어 Amazon.com의 모든 페이지는 150 개 이상의 백엔드 요청으로 구성되어 있으며 귀하를 위해 조립되었습니다. 그것들은 순차적이지 않고 병렬이기 때문에 눈치 채지 못하며 각 "영역"은 자체 웹 서비스입니다.
  • 안정성과 대기 시간이 가장 중요한 앱을 고려하십시오. 각각의 들어오는 요청이 몇 개의 백엔드 요청을 발생시키고 어떤 데이터가 먼저 돌아올 것인지를 원할 것입니다 .
  • 앱에서 수행 한 "클라이언트 가입"을 고려하십시오. "각 요소에 대해 데이터를 얻는다"라고 말하는 대신 많은 고 루틴을 분사 할 수 있습니다. 쿼리 할 슬레이브 DB가 많은 경우 마술처럼 N 배 빠르게 진행됩니다. 그렇지 않으면 더 느리지 않습니다.

스레드 / 프로세스 수가 물리적 코어 수보다 훨씬 큰 경우 적중 감소 리턴

프로그램이 CSP 로 분리되는 유일한 이유는 성능 만이 아닙니다 . 실제로 프로그램을 이해하기 쉽게 만들 수 있으며 코드를 줄이면 일부 문제를 해결할 수 있습니다.

위에 링크 된 슬라이드에서와 같이 코드에서 동시성을 갖는 것이 문제를 구성하는 방법입니다. 고 루틴이없는 것은 당신의 언어로 된지도 / 딕토 네리 / 해시 데이터 구조를 가지고 있지 않은 것과 같습니다. 당신은 그것없이 얻을 수 있습니다. 그러나 일단 당신이 그것을 가지고, 당신은 어디서나 그것을 사용하기 시작하고 정말 프로그램을 단순화합니다.

과거에는 "나만의 롤"멀티 스레드 프로그래밍을 의미했습니다. 그러나 이것은 복잡하고 위험했습니다. 레이스를 만들지 않도록 할 수있는 도구는 아직 많지 않습니다. 그리고 미래의 관리자가 실수하는 것을 어떻게 방지합니까? 대규모 / 복잡한 프로그램을 살펴보면 해당 방향으로 많은 리소스 가 소비되는 것을 볼 수 있습니다.

동시성은 대부분의 언어에서 일류가 아니기 때문에 오늘날의 프로그래머는 왜 유용한 지에 대한 사각 지대를 가지고 있습니다. 이것은 모든 전화와 손목 시계가 1000 코어를 향함에 따라 더욱 분명해질 것입니다. 내장 된 경주 탐지기 도구와 함께 제공됩니다.


2

Erlang의 경우 연결 또는 다른 작업마다 하나의 프로세스를 갖는 것이 일반적입니다. 예를 들어 스트리밍 오디오 서버에는 연결된 사용자 당 1 개의 프로세스가있을 수 있습니다.

Erlang VM은 컨텍스트 스위치를 매우 저렴하게 만들어 수천 또는 수십만 개의 프로세스를 처리하도록 최적화되었습니다.


1

편의. 멀티 스레드 프로그래밍을 시작했을 때 나는 재미를 위해 많은 시뮬레이션과 게임 개발을하고있었습니다. 모든 단일 객체에 대해 스레드를 스핀 오프하고 루프를 통해 각 스레드를 처리하는 대신 자체 작업을 수행하는 것이 매우 편리하다는 것을 알았습니다. 비 결정적 동작으로 인해 코드가 방해받지 않고 충돌이 없으면 코딩이 더 쉬워 질 수 있습니다. 지금 우리가 이용할 수있는 힘으로, 다시 돌아 가면, 수많은 개별 객체를 처리 할 수있는 충분한 처리 능력과 메모리를 가지고 있기 때문에 수천 개의 스레드가 쉽게 분리되는 것을 상상할 수 있습니다!


1

통신을 위해 설계된 Erlang의 간단한 예 : 네트워크 패킷 전송. 하나의 http 요청을 수행하면 수천 개의 TCP / IP 패킷이있을 수 있습니다. 여기에 모두가 동시에 연결하고 사용 사례가 있음을 추가하십시오.

주문 또는 필요한 모든 것을 처리하기 위해 대기업에서 내부적으로 사용하는 많은 응용 프로그램을 고려하십시오. 웹 서버 만이 스레드를 필요로하는 것은 아닙니다.


-2

일부 렌더링 작업은 여기에 떠 오릅니다. 이미지의 모든 픽셀에서 긴 체인의 작업을 수행하고 해당 작업을 병렬화 할 수있는 경우 비교적 작은 1024x768 이미지조차도 "수만"브라켓에 있습니다.


2
몇 년 전, 실시간 FLIR 이미지 처리를 위해 몇 년을 보내면서 초당 30 프레임으로 256x256 이미지를 처리했습니다. 많은 하드웨어 프로세서를 사용하지 않고 데이터를 분할하는 가장 간단한 방법이 아니라면, 마지막으로해야 할 일은 컨텍스트 전환, 메모리 경합 및 캐시 스 래싱을 실제 계산 비용에 추가하는 것입니다.
John R. Strohm

수행중인 작업에 따라 다릅니다. 당신이하고있는 모든 작업을 하드웨어 코어 / 실행 장치로 넘겨주는 것이라면 효과적으로 잊어 버릴 수 있습니다 (이것은 GPU가 작동하는 방식이므로 가상 시나리오가 아닙니다). 유효한.
Maximus Minimus 2013
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.