Ref, Var, Agent, Atom의 Clojure 차이점 (예제 포함)


110

저는 Clojure를 처음 접했습니다. 실제 시나리오에 대해 설명해 주시겠습니까? 내 말은, Ref, Var, Agent, Atom을 어디에 사용할 것인지를 의미합니다. 책을 읽었지만 여전히 실제 사례를 이해할 수 없었습니다.

답변:


174

이 질문에 대한 실제 답변을 위해 "The Joy of Clojure"또는 "programming Clojure"를 적극 권장합니다. 각각에 대한 동기에 대한 짧은 내용을 재현 할 수 있습니다.

정체성의 개념에 대한이 비디오를 시청 하거나 여기서 공부하십시오 .

  • 참조는 "많은 ID"에 대한 조정 된 동기 액세스를 위한 것 입니다.
  • Atom은 단일 ID에 대한 조정 되지 않은 동기식 액세스를위한 것입니다.
  • 에이전트는 단일 ID에 대한 조정 되지 않은 비동기 액세스를위한 것입니다.
  • Vars는 공유 기본값을 사용하는 스레드 로컬 격리 ID 용 입니다.

조정 된 액세스는 두 ID가 함께 변경되어야 할 때 사용됩니다. 전형적인 예는 한 은행 계좌에서 다른 은행 계좌로 돈을 이동하는 것입니다. 완전히 이동하거나 전혀 이동하지 않아야합니다.

조정되지 않은 액세스는 하나의 ID 만 업데이트해야 할 때 사용되며 이는 매우 일반적인 경우입니다.

계속하기 전에 모든 ID가 정산 될 때까지 호출이 대기 할 것으로 예상되는 경우 동기 액세스가 사용됩니다.

비동기 액세스는 "실행 후 잊어 버리기"이며 ID가 자신의 시간에 새로운 상태에 도달하도록합니다.


조정 된 액세스에서 변경 state-a만하고 싶지만 state-b그렇게 할 때 참조 하는 ref경우 에도 올바른 정보 가 필요 합니까? 그래서 그것은 여러 가지를 변경하는 것이 아니라 여러 가지를 참조하면서 그중 하나를 변경하는 것입니까?
event_jr

2
예, state-a의 새 값이 a와 b의 값의 일관된 조합을 기반으로하도록하려면 state-a와 state-b가 모두 refs 여야한다는 것을 올바르게 이해하는 것 같습니다. state-a와 state-b가 서로 일치하는 상황에서 새로운 값을 계산해야합니다. 둘 다 ref 일 때 b가 중간에 변경되면 트랜잭션이 다시 시작되고 a와 b 모두의 새 값을 사용합니다. 이 ensure기능을 보다 명확하고 효율적으로 만들려면 clojure.github.io/clojure/clojure.core-api.html#clojure.core/… 함수를 사용하는 것이 좋습니다.
Arthur Ulfeldt 2015 년

3
기본적으로 공유 된 격리 됨이 무엇을 의미하는지에 대한 설명을 추가하여 답을 완성 할 수 있습니까?
Didier A.

1
"조정 된 액세스는 두 개의 ID를 함께 변경해야 할 때 사용됩니다 ...". "변경"해야합니까?
Carcigenicate

40

Ref는 스레드간에 동기화되어야하는 상태를위한 것입니다. 여러 가지를 추적해야하고 여러 가지를 한 번에 작성하는 작업을 수행해야하는 경우가있는 경우 refs를 사용하십시오. 여러 다른 상태가있을 때마다 ref를 사용하는 것은 나쁜 생각이 아닙니다.

Atom은 스레드간에 동기화되어야하는 독립 상태를위한 것입니다. 원자의 상태와 다른 것을 동시에 변경할 필요가 없다면 at atom을 사용하는 것이 안전합니다 (특히 전체 프로그램에 상태가 하나만있는 경우 원자에 넣을 수 있습니다). . 사소하지 않은 예로서 함수의 반환 값을 캐시 (즉, 메모)하려는 경우 원자를 사용하는 것이 안전 할 수 있습니다. 상태는 함수 외부의 모든 항목에 표시되지 않으므로 걱정할 필요가 없습니다. 함수 내부의 상태 변경에 대해

에이전트의 주요 요점은 다른 스레드에서 실행된다는 것입니다. 에이전트의 값을 가져 와서 해당 값에 함수를 적용하도록 지시 할 수 있지만 함수가 언제 실행 될지 또는 함수가 적용될 값을 알 수 없습니다.

Vars는 스레드별로 무언가를 저장해야 할 때 사용됩니다. 다중 스레드 프로그램이 있고 각 스레드에 자체 개인 상태가 필요한 경우 해당 상태를 var에 넣습니다.

실제 예제가 진행되는 한 수행하려는 작업의 예제를 제공하면 무엇을 사용해야하는지 알려줄 수 있습니다.


32

이러한 유형에 대해 처음 읽었을 때 각 유형을 사용할 수 있거나 사용해야하는 위치를 이해하는 데 어려움을 겪었으므로 여기에 내 평범한 영어 답변이 있습니다.

데이터가 변경되지 않을 때 var를 사용하십시오. 이것은 def또는 def같이 시작하는 대부분의 기능을 사용할 때마다 발생합니다 defn.

변경되는 단일 항목이있을 때 원자를 사용하십시오. 항목을 추가하려는 카운터 또는 벡터를 예로들 수 있습니다.

동시에 변경해야하는 두 개 이상의 항목이있을 때 ref를 사용합니다. 익숙하다면 "데이터베이스 트랜잭션"을 생각하십시오. 이것의 표준적인 예는 한 계좌에서 다른 계좌로 돈을 이체하는 것입니다. 각 계정은 ref에 저장되어 변경 사항이 원자 적으로 표시되도록 할 수 있습니다.

무언가를 바꾸고 싶지만 언제든 상관하지 않을 때 에이전트를 사용하십시오. 이것은 긴 계산이거나 파일 또는 소켓에 무언가를 쓰는 것일 수 있습니다. 후자의 경우 send-off.

참고 : 각각에 대해 훨씬 더 많은 내용이 있다는 점에 감사하지만 이것이 시작점을 제공 할 것입니다.


1
명확한 답변에 감사드립니다 :-) 나 같은 Clojure 초보자를 꽤 많이 돕습니다.
gosukiwi

27

나는 그들 사이의 차이점을 요약하여 기사를 썼고 어떤 것을 사용할 때 선택할 수 있도록 도와줍니다.

공유 상태-vars, atom, agent 및 refs를 사용할 때?

그 주제에 대한 답을 찾는 사람들에게 도움이되기를 바랍니다.

@tunaci 제안 후 기사의 일부 바로 가기 :

Vars

Vars는 모든 스레드에 대해 전역 적입니다.

생성 후 변수를 변경하지 마십시오. 기술적으로 가능하지만 여러 가지 이유로 나쁜 생각입니다.

원자

모든 스레드에 대해 변경 가능한 상태에 대한 액세스를 공유합니다. 변경은 동 기적으로 발생합니다. 다른 스레드가 실행 중에 상태를 변경하면 재 시도하십시오.

장시간 실행시 멱등 함수 및 함수를 사용하지 마십시오.

자치령 대표

모든 스레드에 대해 변경 가능한 상태에 대한 액세스를 공유합니다. 변경은 비동기 적으로 발생합니다.

참조

Refs는 데이터베이스 트랜잭션과 유사하게 작동합니다. 쓰기와 읽기는 dosync에서 보호됩니다. 거래에서 안전한 많은 심판을 운영 할 수 있습니다.

그리고 어느 것을 사용할 때 순서도 : 순서도

일부 업데이트는 항상 가능하므로 웹 사이트의 이미지를 참조하십시오.

복사 및 과거 기사없이 전체 답변을 제공하는 것은 복잡하고 긴 주제이므로 웹 사이트로 리디렉션되는 것을 용서해주십시오 :)


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.