문제

요즘 잠금 장치를 사용하지 않고 Erlang과 같은 메시지 전달 접근법을 사용하는 것에 대해 많은 화제가 있습니다. 또는 기능 프로그래밍과 같은 불변의 데이터 구조와 C ++/Java와 같은 불변의 데이터 구조를 사용합니다.

그러나 내가 걱정하는 것은 다음과 같습니다.

  1. Afaik, Erlang은 메시지 전달을 보장하지 않습니다. 메시지가 손실 될 수 있습니다. 메시지 손실에 대해 걱정해야한다면 알고리즘과 코드가 부풀어 오르지 않으며 다시 복잡하지 않습니까? 사용하는 분산 알고리즘은 보장 된 메시지 전달에 의존해서는 안됩니다.
  2. 메시지가 복잡한 개체라면 어떻게됩니까? 메시지를 복사하고 보내는 데 큰 성과 페널티가 없어서 메시지를 보내는 것과 공유 위치에 보관하십시오 (두 프로세스 모두 액세스 할 수있는 DB와 같이)?
  3. 당신은 정말로 공유 국가를 완전히 빼앗을 수 있습니까? 나는 그렇게 생각하지 않습니다. 예를 들어 DB의 경우 동일한 레코드에 액세스하고 수정해야합니다. 거기에 전달되는 메시지를 사용할 수 없습니다. 낙관적 동시 제어 메커니즘을 잠그거나 가정 한 다음 오류에 대한 롤백을 수행해야합니다. 미분 시아는 어떻게 작동합니까?
  4. 또한 항상 동시성에 대해 걱정 해야하는 경우는 아닙니다. 모든 프로젝트에는 동시성이나 트랜잭션으로 아무것도 할 필요가없는 큰 코드가 있습니다 (그러나 우려로 성능과 속도가 있습니다). 이러한 알고리즘 중 많은 부분이 공유 상태에 달려 있습니다 (따라서 회의 또는 포인터가 유용한 이유).

이 사실을 감안할 때, Erlang 등에 프로그램을 작성하는 것은 이러한 일을하는 것을 막기 때문에 고통입니다. 아마도 프로그램은 강력하지만 선형 프로그래밍 문제를 해결하거나 볼록한 헐릴 등을 계산하는 것과 같은 것들을 위해서는 성능이 더 중요하고 불변성 등을 강요하는 것과 같은 것들이 동시성/거래와 관련이없는 경우 알고리즘에서 불변성 등의 결정이 좋지 않은 결정입니다. . 그렇지 않습니까?

도움이 되었습니까?

해결책

  1. 그것은 실제 생활입니다 : 언어 / 플랫폼에 관계 없이이 가능성을 설명해야합니다. 분산 된 세계 (현실 세계)에서는 실패 : 함께 살아.

  2. 물론 비용이 있습니다: 우리 우주에는 무료가 없습니다. 그러나 통신 파이프에서 "큰 물체"를 셔틀하는 대신 다른 매체 (예 : 파일, DB)를 사용해서는 안됩니까? 항상 "메시지"를 사용하여 어딘가에 저장된 "큰 개체"를 참조 할 수 있습니다.

  3. 물론 : 기능적 프로그래밍의 아이디어 / Erlang OTP의 아이디어는 "분리하십시오"가능한 한이 지역은"공유 상태 "가 조작되었습니다. 장소 공유 상태가 돌연변이되는 곳은 테스트 가능성 및 추적 성을 돕습니다.

  4. 나는 당신이 요점을 놓치고 있다고 생각합니다.은 총알과 같은 것은 없습니다. Erlang을 사용하여 응용 프로그램을 성공적으로 구축 할 수 없다면 그렇게하지 마십시오. 다른 패션에서 전체 시스템의 다른 부분을 항상 다른 언어 / 플랫폼을 사용할 수 있습니다. Erlang 은이 점에서 다른 언어와 다르지 않습니다. 올바른 작업에 적합한 도구를 사용하십시오.

기억하십시오 : Erlang은 해결을 돕기 위해 설계되었습니다 병발 사정, 비동기 그리고 배포 문제. 예를 들어 공유 메모리 블록에서 효율적으로 작업하는 데 최적화되지 않았습니다 ... 인터페이스를 계산하지 않는 한 nif 공유 블록에서 작동하는 기능 게임의 일부 :-)

다른 팁

실제 시스템은 어쨌든 항상 하이브리드입니다: 나는 현대의 패러다임이 실제로 변이 가능한 데이터와 공유 상태를 제거하려고 시도한다고 생각하지 않습니다.

그러나 목표는이 공유 상태에 동시에 접근 할 필요가 없다는 것입니다. 프로그램은 동시 및 순차적으로 나눌 수 있으며 동시 부분에 대한 메시지 통과 및 새로운 패러다임을 사용합니다.

모든 코드가 동일한 투자를받는 것은 아닙니다: 스레드가 근본적으로 "유해하다"은 우려가 있습니다. Apache와 같은 것은 전통적인 동시 스레드가 필요할 수 있으며 이와 같은 주요 기술은 수년에 걸쳐 신중하게 정제 될 수 있으므로 완전히 동시 공유 상태로 폭발 할 수 있습니다. 운영 체제 커널은 "문제가 아무리 비싸더라도 문제를 해결"하는 또 다른 예입니다.

빠르지 않은 파괴에는 이점이 없습니다: 그러나 새 코드 나 그다지주의를 기울이지 않는 코드의 경우 단순히 스레드 안전이 아니며 실제 동시성을 처리하지 않으므로 상대적 "효율성"은 관련이 없습니다. 한 가지 방법은 작동하지만 한 가지 방법은 그렇지 않습니다.

테스트 가능성을 잊지 마십시오 : 또한 테스트에서 어떤 가치를 배치 할 수 있습니까? 스레드 기반 공유 메모리 동시성은 단순히 테스트 할 수 없습니다. 메시지 통과 동시성입니다. 이제 하나의 패러다임을 테스트 할 수는 있지만 다른 패러다임을 테스트 할 수있는 상황이 있습니다. 그렇다면 코드가 테스트되었다는 것을 아는 데있어 가치는 무엇입니까? 모든 상황에서 다른 코드가 작동하는지조차 알지 못하는 위험?

질문에는 몇 가지 암시 적 가정이 있습니다. 모든 데이터가 하나의 컴퓨터에 들어갈 수 있고 응용 프로그램이 본질적으로 한 곳에 국한되어 있다고 가정합니다.

애플리케이션이 너무 커지면 하나의 컴퓨터에 맞지 않으면 어떻게됩니까? 응용 프로그램이 하나의 기계를 능가하면 어떻게됩니까?

하나의 컴퓨터에 맞는 경우 응용 프로그램을 프로그래밍 할 수있는 한 가지 방법을 원하지 않고 하나의 기계를 능가하자마자 완전히 다른 프로그래밍 방식을 프로그래밍하는 방법을 원하지 않습니다.

결함 내성 응용 프로그램을 만들고 싶다면 어떻게됩니까? 결함 내성을 만들려면 적어도 두 개의 물리적으로 분리 된 기계가 필요합니다. 그리고 공유가 없습니다. 공유 및 데이터베이스에 대해 이야기 할 때 MySQL 클러스터와 같은 것들이 물리적으로 분리 된 시스템에서 데이터의 동기화 된 사본을 유지함으로써 결함 불변성을 정확하게 달성한다는 것을 언급하지 않기 위해 생략합니다. 표면 -Erlang은 이것을 드러냅니다.

프로그램 방식은 결함 장애 및 확장 성을 수용하기 위해 갑자기 변경되어서는 안됩니다.

Erlang은 주로 결함 내성 응용 프로그램을 구축하도록 설계되었습니다.

멀티 코어의 공유 데이터 자체 문제 세트가 있습니다. 공유 데이터에 액세스하면 잠금 장치를 획득해야합니다. 글로벌 잠금 장치 (가장 쉬운 접근)를 사용하면 공유에 액세스하는 동안 모든 코어를 중지 할 수 있습니다. 데이터. 캐싱 문제로 인해 멀티 코어의 공유 데이터 액세스가 문제가 될 수 있습니다. 코어에 로컬 데이터 캐시가있는 경우 "멀리 떨어진"데이터 (일부 다른 프로세서 캐시)에 액세스하는 것은 매우 비쌀 수 있습니다.

많은 문제가 본질적으로 분산되며 데이터는 동시에 한 곳에서 사용할 수 없으므로 이러한 종류의 문제는 Erlang 사고 방식과 잘 어울립니다.

분산 설정에서 "메시지 전달 보장"에서 불가능한 - 대상 기계가 충돌했을 수 있습니다. Erlang은 메시지 전달을 보장 할 수 없습니다. 다른 접근 방식이 필요합니다. 시스템은 메시지를 전달하지 못한 지 (링크 메커니즘을 사용한 경우에만) 자신의 사용자 지정 오류 복구를 작성할 수 있습니다.)

순수한 숫자 크런치의 경우 Erlang은 적절하지 않습니다. 그러나 하이브리드 시스템에서 Erlang은 계산이 사용 가능한 프로세서에 분산되는 방법을 관리하는 데 능숙하므로 Erlang이 문제의 분포 및 결함이 강한 측면을 관리하는 많은 시스템을 볼 수 있습니다. 문제 자체는 다른 언어로 해결됩니다.

다른 언어가 사용됩니다

Erlang에 대한 오해에 대한 몇 가지 의견 :

  • Erlang은 메시지가 손실되지 않으며 전송 된 주문에 도착할 것을 보장합니다. 기본 오류 상황은 기계 A가 기계 B에 말할 수 없다는 것입니다.이 경우 프로세스 모니터 및 링크가 트리거되고 시스템 노드 다운 메시지가 등록 된 프로세스로 전송됩니다. 조용히 떨어지지 않을 것입니다. 프로세스는 "충돌"하고 감독자 (있는 경우)는이를 다시 시작하려고합니다.
  • 물체는 돌연변이 될 수 없으므로 항상 복사됩니다. 불변성을 확보하는 한 가지 방법은 다른 Erlang 프로세스 힙에 값을 복사하는 것입니다. 또 다른 방법은 공유 힙에 객체를 할당하고, 메시지를 참조하고 단순히 돌연변이하는 작업이없는 것입니다. Erlang 공연을위한 첫 번째! 모든 프로세스가 쓰레기를 수집하기 위해 공유 힙을 수집 해야하는 경우 실시간으로 어려움을 겪습니다. Java에게 물어보세요.
  • Erlang에는 공유 상태가 있습니다. Erlang은 그것을 자랑스럽게 생각하지 않지만 그것에 대해 실용적입니다. 한 가지 예는 시스템 프로세스를 다시 시작하고 이전 이름을 청구 할 수 있도록 프로세스에 이름을 매핑하는 글로벌 맵인 로컬 프로세스 레지스트리입니다. Erlang 그냥 가능하다면 공유 상태를 피하려고 시도합니다. 공개 된 ETS 테이블도 또 다른 예입니다.
  • 예, 때로는 Erlang이 너무 느립니다. 이것은 모든 언어가 발생합니다. 때로는 자바가 너무 느립니다. 때로는 C ++가 너무 느립니다. 게임의 단단한 루프가 심각한 Simd 기반 벡터 수학을 시작하기 위해 어셈블리로 내려 가야했기 때문에 모든 것이 어셈블리로 작성되어야한다고 추론 할 수는 없습니다. 중요한 것은 성능이 좋은 시스템을 작성할 수 있다는 것입니다. Erlang은 상당히 잘 관리합니다. YAWS 또는 RabbitMQ의 벤치 마크를 참조하십시오.

당신의 사실은 Erlang에 대한 사실이 아닙니다. Erlang 프로그래밍이 고통 스럽다고 생각하더라도 다른 사람들이 그 덕분에 멋진 소프트웨어를 만들 수 있습니다. Erlang에 IRC 서버를 작성하거나 매우 동시에 쓰기를 시도해야합니다. 다시는 Erlang을 사용하지 않더라도 동시성에 대해 다른 방법으로 생각하는 법을 배웠을 것입니다. 그러나 물론 Erlang은 굉장하기 때문에 당신은 할 것입니다.

Erlang을 이해하지 못하는 사람들은 그것을 심하게 재 구현 할 운명입니다.

좋아, 원본은 LISP에 관한 것이었지만 ... 사실!

예를 들어 DB의 경우 동일한 레코드에 액세스하고 수정해야합니다.

그러나 그것은 DB에 의해 처리됩니다. 데이터베이스 사용자로서 간단히 쿼리를 실행하고 데이터베이스는이를 분리하여 실행하도록합니다.

성능과 관련하여 공유 상태를 제거하는 데있어 가장 중요한 것 중 하나는 새로운 최적화를 가능하게한다는 것입니다. 공유 상태는 특별히 효율적이지 않습니다. 동일한 캐시 라인을 통해 코어와 싸우는 코어를 얻을 수 있으며 데이터가 레지스터 또는 CPU 캐시에 머무를 수있는 메모리를 통해 데이터를 작성해야합니다.

많은 컴파일러 최적화는 부작용과 공유 상태에도 의존합니다.

이러한 것들을 보장하는 더 엄격한 언어는 C와 같은 것보다 더 많은 최적화가 필요하다고 말할 수 있지만, 이러한 최적화는 컴파일러가 훨씬 쉽게 구현할 수있게 해줍니다.

동시성 문제와 유사한 많은 우려는 단일 레드 리드 코드에서 발생합니다. 최신 CPU는 파이프 라인되어 있으며 순서대로 지침을 실행하며 주기당 3-4를 실행할 수 있습니다. 따라서 단일 스레드 프로그램에서도 컴파일러와 CPU가 어떤 명령을 인터리브하고 병렬로 실행할 수 있는지 결정할 수 있습니다.

  1. Erlang은 동기 호출에 대한 감독자 및 Gen_Server 콜백을 제공하므로 메시지가 전달되지 않으면 알 수 있습니다. Gen_Server 호출이 타임 아웃을 반환하거나 전체 노드가 내려와 감독자가 트리거되면 위로 올립니다.
  2. 일반적으로 프로세스가 동일한 노드에있는 경우 메시지 통과 언어는 데이터 복사를 최적화하므로 공유 메모리를 사용하여 공유 메모리를 사용하여 수행 할 수없는 경우를 제외하고는 공유 메모리와 거의 비슷합니다.
  3. 재귀적인 꼬리 통로에서 자신을 전달함으로써 프로세스에 의해 보관되는 일부 상태가 있으며, 일부 상태는 물론 메시지를 통과 할 수 있습니다. 나는 MNESIA를 많이 사용하지 않지만 거래 데이터베이스이므로, 일단 운영을 MNESIA로 통과 한 후에 (그리고 반환 됨), 당신은 그것이 통과 할 것이라고 거의 보장 할 것입니다.
  4. 그렇기 때문에 포트 나 드라이버를 사용하여 이러한 응용 프로그램을 Erlang에 쉽게 묶을 수 있습니다. 가장 쉬운 것은 포트입니다. 유닉스 파이프와 매우 흡사합니다. 성능은 그다지 좋지 않다고 생각합니다. 그리고 말했듯이, 메시지 통과는 일반적으로 VM/컴파일러가 메모리 사본을 최적화하는 것처럼 어쨌든 포인터를 통과하는 것만으로 끝납니다. .

정확성을 위해 공유는 갈 수있는 방법이며 데이터를 가능한 한 정규화합니다. 즉각적인 경우, 변경 사항을 알리기 위해 메시지를 보내지 만 항상 폴링으로 백업하십시오. 메시지가 삭제, 복제, 재정렬, 지연 - 의존하지 마십시오.

속도가 당신이 걱정하는 것이라면 먼저 싱글 스레드를하고 일광을 조정하십시오. 그런 다음 여러 코어가 있고 작업을 분할하는 방법을 알고 있다면 병렬 처리를 사용하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top