Clojure-동시 프로그래밍
Clojure 프로그래밍에서 대부분의 데이터 유형은 변경 불가능하므로 동시 프로그래밍의 경우 이러한 데이터 유형을 사용하는 코드는 코드가 여러 프로세서에서 실행될 때 매우 안전합니다. 그러나 여러 번 데이터를 공유해야하는 요구 사항이 있으며 여러 프로세서에서 데이터를 공유하는 경우 여러 프로세서로 작업 할 때 데이터 상태가 무결성 측면에서 유지되는지 확인해야합니다. 이것은concurrent programming Clojure는 이러한 프로그래밍을 지원합니다.
dosync, ref, set, alter 등을 통해 노출되는 소프트웨어 트랜잭션 메모리 시스템 (STM)은 동기식 및 조정 된 방식으로 스레드간에 변경 상태 공유를 지원합니다. 에이전트 시스템은 비동기적이고 독립적 인 방식으로 스레드 간의 변경 상태 공유를 지원합니다. 원자 시스템은 동기적이고 독립적 인 방식으로 스레드 간의 변경 상태 공유를 지원합니다. def, binding 등을 통해 노출되는 동적 var 시스템은 스레드 내에서 상태 변경 격리를 지원합니다.
다른 프로그래밍 언어도 동시 프로그래밍 모델을 따릅니다.
변경 될 수있는 데이터에 대한 직접적인 참조가 있습니다.
공유 액세스가 필요한 경우 개체가 잠기고 값이 변경되며 해당 값에 대한 다음 액세스를 위해 프로세스가 계속됩니다.
Clojure에는 잠금이 없지만 변경 불가능한 영구 데이터 구조에 대한 간접 참조가 있습니다.
Clojure에는 세 가지 유형의 참조가 있습니다.
Vars − 변경 사항은 스레드에서 격리됩니다.
Refs − 변경 사항은 스레드간에 동기화되고 조정됩니다.
Agents − 스레드 간의 비동기 독립 변경을 포함합니다.
동시 프로그래밍과 관련하여 Clojure에서 다음 작업이 가능합니다.
업무
Clojure의 동시성은 트랜잭션을 기반으로합니다. 참조는 트랜잭션 내에서만 변경할 수 있습니다. 거래에는 다음과 같은 규칙이 적용됩니다.
- 모든 변경은 원자 적이며 격리되어 있습니다.
- 참조에 대한 모든 변경은 트랜잭션에서 발생합니다.
- 어떤 거래도 다른 거래의 효과를 보지 못합니다.
- 모든 트랜잭션은 dosync 블록 내부에 배치됩니다.
우리는 이미 dosync 블록이하는 일을 보았습니다. 다시 살펴 보겠습니다.
dosync
표현식 및 중첩 된 호출을 포함하는 트랜잭션에서 표현식 (암시 적 do에서)을 실행합니다. 이 스레드에서 이미 실행중인 트랜잭션이 없으면 트랜잭션을 시작합니다. 잡히지 않은 예외는 트랜잭션을 중단하고 dosync에서 흘러 나옵니다.
다음은 구문입니다.
통사론
(dosync expression)
Parameters − 'expression'은 dosync 블록에 들어올 표현식 집합입니다.
Return Value − 없음.
참조 변수의 값을 변경하는 예를 살펴 보겠습니다.
예
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def names (ref []))
(alter names conj "Mark"))
(Example)
산출
위의 프로그램을 실행하면 다음과 같은 오류가 발생합니다.
Caused by: java.lang.IllegalStateException: No transaction running
at clojure.lang.LockingTransaction.getEx(LockingTransaction.java:208)
at clojure.lang.Ref.alter(Ref.java:173)
at clojure.core$alter.doInvoke(core.clj:1866)
at clojure.lang.RestFn.invoke(RestFn.java:443)
at clojure.examples.example$Example.invoke(main.clj:5)
at clojure.examples.example$eval8.invoke(main.clj:7)
at clojure.lang.Compiler.eval(Compiler.java:5424)
... 12 more
오류를 통해 먼저 트랜잭션을 시작하지 않으면 참조 유형의 값을 변경할 수 없음을 분명히 알 수 있습니다.
위의 코드가 작동하려면 다음 프로그램에서 수행 한 것처럼 dosync 블록에 alter 명령을 배치해야합니다.
예
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def names (ref []))
(defn change [newname]
(dosync
(alter names conj newname)))
(change "John")
(change "Mark")
(println @names))
(Example)
위의 프로그램은 다음과 같은 출력을 생성합니다.
산출
[John Mark]
dosync의 또 다른 예를 보겠습니다.
예
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def var1 (ref 10))
(def var2 (ref 20))
(println @var1 @var2)
(defn change-value [var1 var2 newvalue]
(dosync
(alter var1 - newvalue)
(alter var2 + newvalue)))
(change-value var1 var2 20)
(println @var1 @var2))
(Example)
위의 예에서는 dosync 블록에서 변경되는 두 개의 값이 있습니다. 트랜잭션이 성공하면 두 값이 모두 변경되고 그렇지 않으면 전체 트랜잭션이 실패합니다.
위의 프로그램은 다음과 같은 출력을 생성합니다.
산출
10 20
-10 40