멀티 스레딩이 어려운 이유를 설명하는 방법


84

나는 상당히 좋은 프로그래머이고, 상사는 또한 아주 좋은 프로그래머입니다. 그는 멀티 스레딩과 같은 일부 작업을 과소 평가하는 것처럼 보이지만 얼마나 어려운지 (아마도 몇 개의 스레드를 실행하고 모두가 완료되기를 기다린 다음 결과를 반환하는 것보다 매우 어렵다는 것을 알았습니다).

교착 상태와 경쟁 조건에 대해 걱정하기 시작한 순간, 나는 그것이 매우 어렵다는 것을 알지만, 사장님은 이것을 이해하지 못하는 것 같습니다-나는 그가 이것을 본 적이 있다고 생각하지 않습니다. 그것에 자물쇠를 때리는 것은 거의 태도입니다.

그렇다면 동시성, 병렬 처리 및 멀티 스레딩의 복잡성을 과소 평가하는 이유를 어떻게 설명하거나 설명 할 수 있습니까? 아니면 내가 틀렸을 까?

편집 : 그가 한 일에 대해 조금-목록을 반복하면 해당 목록의 각 항목에 대해 해당 항목의 정보를 기반으로 데이터베이스 업데이트 명령을 실행하는 스레드가 생성됩니다. 그가 한 번에 얼마나 많은 스레드를 실행했는지 제어 할 수 있는지 잘 모르겠습니다. 실행이 너무 많으면 (세마포어를 사용하지 않았을 때) 대기열에 추가해야합니다.


17
멀티 스레딩은 쉽습니다. 올바른 동기화가 어렵습니다.
Vineet Reynolds

33
바람직하게는 다른 억양으로 세 사람을 방으로 데려 가서 동시성 문제의 다른 부분과 겹치는 부분을 동시에 설명하십시오.
greyfade

멀티 스레딩은 당면한 문제와 언어 지원에 따라 매우 어렵거나 매우 쉽습니다. Clojure를 사용하면 쉽게 clojure.org/concurrent_programming
Job

4
@Job 동시 프로그래밍은 사용하는 언어에 관계없이 항상 어렵습니다 (실제 프로젝트에서는). Scala, Clojure 또는 Erlang은 변경 가능한 상태를 사용하고 장려하는 언어와 비교하려고 할 때 약간 제정신입니다.
Chiron

4
이것에 대한 내가 가장 좋아하는 은유는 : "수면제와 완하제를 동시에 복용하겠습니까?" 복잡한 메시지 큐를 사용하여, 순서는 동시성의 열매입니다 바르게은 . 당신이하지 않는 한 즉, 멋진 그것은 경험의 거래를한다 하드 많은 사람들.
Tim Post

답변:


29
  1. 수학적 경험을 믿을 수 있다면, 기계 명령어의 가능한 모든 인터리빙이 여전히 옳은 일을해야하기 때문에 본질적으로 결정적인 정상적인 실행 흐름이 여러 스레드에서 비 결정적이지 않고 지수 적으로 복잡 해지는 방법을 설명하십시오. 업데이트 손실 또는 더티 읽기 상황의 간단한 예는 종종 눈을 뜨게하는 것입니다.

  2. "잠금 해제" 사소한 해결책입니다 ... 성능에 관심이없는 경우 모든 문제를 해결합니다 . 예를 들어 애틀랜타에있는 누군가가 한 권의 책을 주문할 때마다 아마존이 동해안 전체를 잠그어야했을 때 얼마나 많은 성능 저하가 발생했는지 설명해보십시오!


1
수학적 복잡성에 대한 +1-공유 상태 동시성의 어려움을 이해하게 된 방법이며 메시지 전달 아키텍처를 옹호 할 때 일반적으로 내리는 주장입니다. -1은 "잠금 해제"에 대한 것입니다 ...이 문구는 잠금 사용에 대해 생각하지 않은 접근 방식을 의미하며 교착 상태 또는 일관성없는 동작으로 이어질 수 있습니다 (다른 스레드에있는 코드 클라이언트가 충돌 할 경우) 요청이 있지만 서로 동기화되지 않으면 클라이언트는 호환되지 않는 라이브러리 상태 모델을 갖게됩니다.
Aidan Cully

2
아마존 주문을 처리하는 동안 하나의 창고에서 개별 품목의 재고를 잠깐 잠글 필요가 있습니다. 하나의 특정 품목에 대해 갑작스럽고 큰 실행이 발생하는 경우 공급이 고갈되고 재고에 대한 액세스가 읽기 전용 (100 % 공유 가능)이 될 때까지 해당 품목의 주문 성능이 저하됩니다. 아마존이 다른 프로그램에서 할 수없는 일 중 하나는 재입고가 발생할 때까지 주문을 대기하는 기능과 새로운 주문에 재입고가 가능하기 전에 대기중인 주문을 처리하는 옵션입니다.
Blrfl

@Blrfl : 큐를 통한 메시지 전달을 사용하도록 작성된 경우 프로그램에서 이를 수행 할 수 있습니다. 단일 대기열을 통해 특정 스레드에 대한 모든 메시지를 가질 필요는 없습니다…
Donal Fellows

4
@Donal Fellows : 하나의 창고에 1M 위젯이 있고 1M 주문이 같은 순간에 도착하는 경우, 모든 요청은 처리 방식에 관계없이 주문과 품목을 일치시키면서 일정 수준으로 직렬화됩니다. 실질적인 현실은 아마존에 재고가 너무 많은 위젯을 보유한 적이 없기 때문에 재고가 소진되기 전에 대량의 주문을 처리하는 데 걸리는 지연 시간이 용납 될 수 없을 정도로 높아지고 다른 모든 사람에게 (병렬로) 알려줄 수 있다는 것입니다. " 메시지 대기열은 교착 상태를 방지하는 좋은 방법이지만 제한된 리소스에 대한 높은 경합 문제를 해결하지는 못합니다.
Blrfl

79

멀티 스레딩 간단합니다. 멀티 스레딩을위한 응용 프로그램 코딩은 매우 쉽습니다.

간단한 트릭이 있습니다. 이것은 잘 설계된 메시지 큐 ( 자신의 롤을 하지 마십시오 )를 사용하여 스레드간에 데이터를 전달하는 것입니다.

어려운 부분은 여러 스레드가 마술처럼 공유 객체를 어떤 식 으로든 업데이트하려고합니다. 사람들은 존재하는 경쟁 조건에주의를 기울이지 않기 때문에 오류가 발생하기 쉽습니다.

많은 사람들이 메시지 대기열을 사용하지 않고 공유 객체를 업데이트하고 스스로 문제를 만듭니다.

어려운 점은 여러 큐간에 데이터를 전달할 때 잘 작동하는 알고리즘을 설계하는 것입니다. 어렵습니다. 그러나 공존 스레드 (공유 큐를 통한)의 메커니즘은 쉽습니다.

또한 스레드 I / O 리소스를 공유 합니다. I / O 바운드 프로그램 (예 : 네트워크 연결, 파일 작업 또는 데이터베이스 작업)은 많은 스레드로 더 빨리 진행되지는 않습니다.

공유 객체 업데이트 문제를 설명하려면 간단합니다. 여러 장의 종이 카드로 테이블을 가로 질러 앉습니다. 페이지 아래에 공간이 많은 간단한 계산 세트 (4 개 또는 6 개의 간단한 수식)를 작성하십시오.

여기 게임이 있습니다. 당신은 각각 공식을 읽고, 답을 쓰고, 답과 함께 카드를 내려 놓습니다.

여러분 각자가 절반의 일을 할 것입니다. 반 시간에 끝났어요?

당신의 상사가 많이 생각하지 않고 시작하면, 당신은 어떤 식 으로든 갈등을 일으키고 같은 공식에 대한 답을 쓰게됩니다. 글쓰기 전에 읽은 두 사람 사이에 본질적인 경쟁 조건이 있기 때문에 작동하지 않았습니다. 같은 공식을 읽고 서로의 답변을 덮어 쓰는 것을 막을 수있는 것은 없습니다.

리소스를 잘못 또는 잠금 해제하여 경쟁 조건을 만드는 방법은 여러 가지가 있습니다.

모든 충돌을 피하려면 용지를 수식 묶음으로 자릅니다. 대기열에서 하나를 가져 와서 답을 적고 답을 게시하십시오. 하나의 독자 전용 메시지 큐에서 읽기 때문에 충돌이 없습니다.


종이를 쌓아 두어도 완전히 고쳐지지는 않습니다. 여전히 당신과 당신의 상사가 새로운 공식에 도달하여 너클을 그의 것으로 where는 상황이 여전히 있습니다. 사실, 이것은 가장 일반적인 종류의 스레딩 문제를 나타냅니다. 실제로 심각한 오류가 일찍 발견됩니다. 이 오류와 같은 그럴듯한 경쟁 조건은 테스트 과정에서 계속 발생하고 결국에는 대부분 (또는 대부분의 경우) 다림질됩니다.
Airsource Ltd

@AirsourceLtd "너클 너클을 그에게 부딪쳤다"는 말이 정확히 무엇입니까? 두 개의 다른 스레드가 동일한 메시지를 가져 가지 못하게하는 메시지 큐가 있으면 문제가되지 않습니다. 내가 무슨 뜻인지 오해하지 않는 한
Zack

25

다중 스레드 프로그래밍은 동시성에 가장 어려운 솔루션 일 것입니다. 기본적으로 기계가 실제로하는 일의 상당히 낮은 수준의 추상화입니다.

액터 모델 또는 (소프트웨어) 트랜잭션 메모리 와 같이 훨씬 쉬운 여러 가지 접근 방식 이 있습니다. 또는 목록 및 트리와 같은 불변 데이터 구조를 사용하여 작업합니다.

일반적으로 문제를 적절히 분리하면 멀티 스레딩이 더 쉬워집니다. 사람들이 20 개의 스레드를 생성 할 때 모두 동일한 버퍼를 처리하려고 시도 할 때 종종 잊어 버리게됩니다. 동기화가 필요한 리액터를 사용하고 일반적으로 메시지 대기열이있는 다른 작업자 간에 데이터를 전달하십시오 .
응용 프로그램 논리에 잠금이 있으면 문제가있는 것입니다.

따라서 기술적으로 멀티 스레딩은 어렵습니다.
"잠금 해제"는 동시성 문제에 대한 확장 성이 가장 적은 솔루션이며 실제로 멀티 스레딩의 전체 목적을 무효화합니다. 문제는 비 동시 실행 모델로 문제를 되 돌리는 것입니다. 더 많이할수록 한 번에 하나의 스레드 만 실행됩니다 (또는 교착 상태에서는 0). 그것은 모든 목적을 무너 뜨립니다.
"제 3 세계의 문제를 해결하는 것은 쉽다. 폭탄을 던져라." 사소한 해결책이 있기 때문에 결과의 품질을 염두에두기 때문에 문제가 사소한 것이 아닙니다.

그러나 실제로 이러한 문제를 해결하는 것은 다른 프로그래밍 문제와 마찬가지로 어렵고 적절한 추상화로 수행하는 것이 가장 좋습니다. 실제로는 매우 쉽습니다.


14

나는이 질문에 기술적 비 각도가 있다고 생각합니다-IMO는 신뢰의 문제입니다. 우리는 일반적으로 Facebook과 같은 복잡한 앱을 재생산하라는 요청을받습니다. 시작하지 않은 / 관리자에게 작업의 복잡성을 설명해야한다면 덴마크에서 썩은 것이 있다는 결론에 도달했습니다.

다른 닌자 프로그래머가 5 분 안에 작업을 수행 할 수 있다고해도 추정치는 개인의 능력에 근거한 것입니다. 귀하의 대담자는 문제에 대한 귀하의 의견을 신뢰하거나 기꺼이 받아 들일 사람을 고용해야합니다.

문제는 사람들이 대화를 통해 무시하거나 파악할 수없는 기술적 함의를 전달하는 것이 아니라 상호 존중의 관계를 확립하는 데 있습니다.


1
흥미로운 질문이지만 기술적 인 질문입니다. 그러나 나는 당신이 말한 것에 동의합니다 ...이 경우, 내 매니저는 꽤 좋은 프로그래머입니다. 그러나 그는 멀티 스레드 응용 프로그램의 복잡성을 발견하지 못했기 때문에 과소 평가합니다.
Mr Shoubs

6

교착 상태를 이해하기위한 간단한 사고 실험은 " 식사 철학자 "문제입니다. 경쟁 조건이 얼마나 나빠질 수 있는지 설명하는 데 사용하는 예제 중 하나는 Therac 25 상황입니다.

"그냥 잠그는 것"은 멀티 스레딩으로 어려운 버그를 겪지 않은 사람의 사고 방식입니다. 그리고 그는 당신이 상황의 심각성을 과장하고 있다고 생각할 수도 있습니다 (그렇지 않습니다-경쟁 조건 버그가있는 사람들, 특히 자동차에 내장 된 소프트웨어로 물건을 날려 버릴 수 있습니다).


1
즉, 샌드위치 문제 : 샌드위치 더미를 만들지 만 버터 접시와 나이프는 1 개뿐입니다. 일반적으로 모두 괜찮지 만 결국 누군가는 칼을 잡고 다른 사람은 칼을 움켜 쥐게됩니다. 그리고 그들은 다른 사람이 그들의 자원을 놓을 때까지 기다립니다.
gbjbaanb 2016 년

항상 정해진 순서대로 리소스를 확보하여 이와 같은 교착 상태 문제를 해결할 수 있습니까?
compman

@compman. 2 개의 스레드가 동시에 동일한 리소스를 가져 오려고 시도 할 수 있기 때문에 해당 스레드는 반드시 동일한 리소스 집합을 필요로하지는 않으며 문제를 일으킬 정도로 겹치기 만하면됩니다. 한 가지 방법은 리소스를 "다시"넣은 다음 임의 기간 동안 기다렸다가 다시 잡는 것입니다. 이 백 오프 기간은 여러 프로토콜에서 발생하며, 가장 초기 프로토콜은 Aloha입니다. en.wikipedia.org/wiki/ALOHAnet
Tangurena 2016

1
프로그램의 모든 리소스에 숫자가 있고 스레드 / 프로세스에 리소스 세트가 필요한 경우 항상 숫자 순서대로 리소스를 잠급니다. 교착 상태가 발생할 수 있다고 생각하지 않습니다.
compman

1
@ compman : 실제로 교착 상태를 피하는 방법입니다. 이를 자동으로 확인할 수있는 도구를 설계 할 수 있습니다. 따라서 응용 프로그램에서 숫자 순서가 아닌 다른 리소스를 잠그지 않는 경우 잠재적 교착 상태가 발생 하지 않습니다 . (잠재적 교착 상태는 코드가 고객의 컴퓨터에서 실행될 때만 실제 교착 상태로 바뀝니다).
gnasher729 2016 년

3

동시 응용 프로그램은 결정적이지 않습니다. 프로그래머가 취약한 것으로 인식하는 매우 적은 양의 전체 코드를 사용하면 스레드 / 프로세스의 일부가 다른 스레드의 일부와 관련하여 실행될시기를 제어 할 수 없습니다. 테스트가 더 어렵고 시간이 오래 걸리며 동시성 관련 결함을 모두 찾을 수는 없습니다. 결함이 발견되는 경우, 미묘한 결함을 일관되게 재현 할 수 없으므로 수정이 어렵다.

따라서 유일하게 올바른 동시 응용 프로그램은 소프트웨어 개발에서 종종 실행되지 않는 올바른 응용 프로그램입니다. 결과적으로 S.Lot의 대답은 메시지 전달이 상대적으로 정확하다는 것이 상대적으로 쉬운 것이기 때문에 가장 일반적인 조언입니다.


3

두 단어로 된 짧은 대답 : 관찰 불가능 비 결정적

긴 대답 : 문제가있을 때 사용하는 동시 프로그래밍 방법에 따라 다릅니다. 책에서 컴퓨터 프로그래밍의 개념, 기술 및 모델 , 저자는 명확 동시 프로그램을 작성하는 네 가지 실천 방법을 설명합니다 :

  • 순차적 프로그래밍 : 동시성이없는 기본 접근 방식.
  • 선언적 동시성 : 관찰 가능한 비결 정성이없는 경우에 사용 가능합니다.
  • 메시지 전달 동시성 : 많은 엔티티간에 동시 메시지 전달. 각 엔티티는 내부적으로 메시지를 순차적으로 처리합니다.
  • 공유 상태 동시성 : 잠금, 모니터 및 트랜잭션과 같은 거친 원자 동작을 통해 공유 수동 객체를 업데이트하는 스레드;

명백한 순차적 프로그래밍 외에이 네 가지 방법 중 가장 쉬운 방법은 선언적 동시성 입니다. 이 방법을 사용하여 작성된 프로그램 에는 관찰 가능한 비결 정성 이 없기 때문 입니다. 즉, 경쟁 조건은 관찰 가능한 비 결정적 행동이기 때문에 경쟁 조건이 없습니다 .

그러나 관찰 가능한 비결정론이 없다는 것은 선언적 동시성을 사용하여 해결할 수없는 몇 가지 문제 가 있음을 의미 합니다. 마지막 두 가지 쉬운 접근 방식이 적용되는 곳입니다. 쉽지 않은 부분은 관찰 가능한 비결정론의 결과입니다. 이제 둘 다 상태 저장 동시 모델에 속하며 표현력도 동일합니다. 그러나 CPU 당 코어 수의 증가로 인해 메시지 전달 라이브러리 (예 : Akka for JVM) 또는 프로그래밍 언어 (예 : Erlang ) 의 증가에서 볼 수 있듯이 업계는 최근 메시지 전달 동시성에 더 많은 관심을 보인 것으로 보입니다. .

이론적 Actor 모델이 지원하는 앞서 언급 한 Akka 라이브러리는 더 이상 잠금, 모니터 또는 트랜잭션을 처리 할 필요가 없으므로 동시 애플리케이션 빌드를 단순화합니다. 다른 한편으로는, 액터를 계층 적으로 합성하는 방법으로 생각하는 솔루션 설계에 대한 다른 접근법이 필요합니다. 완전히 다른 사고 방식이 필요하다고 말할 수 있는데, 이는 다시 일반 상태 공유 동시성을 사용하는 것보다 훨씬 어려울 수 있습니다.

동시 프로그래밍 관찰 가능한 비결정론으로 인해 어렵지만 주어진 문제에 대한 올바른 접근 방식과 해당 접근 방식을 지원하는 올바른 라이브러리를 사용하면 많은 문제를 피할 수 있습니다.


0

나는 2 개의 스레드를 시작한 간단한 프로그램을보고 1-100에서 동시에 콘솔에 인쇄하도록함으로써 문제를 일으킬 수 있다고 처음 배웠다. 대신에:

1
1
2
2
3
3
...

다음과 같은 것을 얻습니다.

1
2
1
3
2
3
...

다시 실행하면 완전히 다른 결과를 얻을 수 있습니다.

우리 대부분은 코드가 순차적으로 실행될 것이라고 가정하도록 훈련을 받았습니다. 대부분의 멀티 스레딩에서는 당연히 "즉시 사용"할 수 없습니다.


-3

망치를 쥐고있는 사람들 사이의 의사 소통없이 몇 개의 망치를 사용하여 밀접하게 간격을 둔 손톱을 한 번에 으깨십시오.

집을 짓기 위해 이관하십시오.

밤에 잠을 자려고한다면 당신이 건축가라고 상상해보십시오. :)


-3

쉬운 부분 : 세마포어, 대기열, 연동 카운터, 원자 상자 유형 등과 같은 프레임 워크, 운영 체제 및 하드웨어의 최신 기능을 갖춘 멀티 스레딩을 사용하십시오.

어려운 부분 : 처음에는 기능을 사용하지 않고 기능을 직접 구현하십시오. 하드웨어의 매우 제한된 기능을 제외하고는 여러 코어에서 클록 일관성 보장에만 의존합니다.


3
어려운 부분은 실제로 더 어렵지만 그 쉬운 부분조차 그렇게 쉽지 않습니다.
PeterAllenWebb 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.