함수형 프로그래밍 ¹은 때때로 그런 식으로 표현 되기는하지만 상태 저장 계산을 방해하지는 않습니다. 프로그래머가 상태를 명시 적으로 만들도록 강제하는 것입니다.
예를 들어, 의사 대기열 (일부 의사 언어)을 사용하여 일부 프로그램의 기본 구조를 살펴 보겠습니다.
q := Queue.new();
while (true) {
if (Queue.is_empty(q)) {
Queue.add(q, producer());
} else {
consumer(Queue.take(q));
}
}
기능적 큐 데이터 구조를 가진 해당 구조 (여전히 한 가지 차이점을 해결하기 위해 명령형 언어로)는 다음과 같습니다.
q := Queue.empty;
while (true) {
if (q = Queue.empty) {
q := Queue.add(q, producer());
} else {
(tail, element) := Queue.take(q);
consumer(element);
q := tail;
}
}
대기열은 이제 변경할 수 없으므로 객체 자체는 변경되지 않습니다. 이 의사 코드에서 q
자체는 변수입니다. 할당 q := Queue.add(…)
하고 q := tail
다른 객체를 가리 킵니다. 큐 함수의 인터페이스가 변경되었습니다. 각각은 조작의 결과 인 새 큐 오브젝트를 리턴해야합니다.
순전히 기능적인 언어, 즉 부작용이없는 언어에서는 모든 상태를 명시 적으로 만들어야합니다. 생산자와 소비자가 아마도 무언가를하고 있기 때문에, 그들의 상태는 여기서도 발신자의 인터페이스에 있어야합니다.
main_loop(q, other_state) {
if (q = Queue.empty) {
let (new_state, element) = producer(other_state);
main_loop(Queue.add(q, element), new_state);
} else {
let (tail, element) = Queue.take(q);
let new_state = consumer(other_state, element);
main_loop(tail, new_state);
}
}
main_loop(Queue.empty, initial_state)
이제 모든 상태 조각이 어떻게 명시 적으로 관리되는지 확인하십시오. 큐 조작 기능은 큐를 입력으로 사용하고 새 큐를 출력으로 생성합니다. 생산자와 소비자도 그들의 상태를 통과합니다.
동시 프로그래밍은 잘 맞지 않는 내부 함수형 프로그래밍,하지만 아주 잘 맞는 주위 함수형 프로그래밍을. 아이디어는 여러 개의 개별 계산 노드를 실행하고 메시지를 교환하도록하는 것입니다. 각 노드는 기능적 프로그램을 실행하며 메시지를 송수신 할 때 상태가 변경됩니다.
예제를 계속하면 하나의 큐가 있기 때문에 하나의 특정 노드에서 관리합니다. 소비자는 해당 노드에 요소를 얻기 위해 메시지를 보냅니다. 생산자는 해당 노드에 요소를 추가하라는 메시지를 보냅니다.
main_loop(q) =
consumer->consume(q->take()) || q->add(producer->produce());
main_loop(q)
동시성을 올바르게 얻는“산업화 된”언어는 Erlang 입니다. Erlang을 배우는 것은 동시 프로그래밍에 대한 깨달음의 길입니다.
모두 부작용없는 언어로 전환하십시오!
¹ 이 용어에는 몇 가지 의미가 있습니다. 여기서 나는 부작용없이 프로그래밍을 의미하기 위해 그것을 사용하고 있다고 생각하며, 이것이 또한 내가 사용하고있는 의미입니다.
² 암시 적 상태의 프로그래밍 은 명령형 프로그래밍입니다 . 객체 방향은 완전히 직교하는 문제입니다.
³ 염증성, 나는 알고 있지만, 나는 그것을 의미합니다. 공유 메모리가있는 스레드는 동시 프로그래밍의 어셈블리 언어입니다. 메시지 전달은 이해하기 훨씬 쉬우 며 동시성 기능을 도입하자마자 부작용의 부재가 실제로 빛납니다.
⁴ 그리고 이것은, 얼랑의 팬이 아니라 누군가하지만 다른 이유로오고있다.