[clojure] Clojure 에이전트와 무분별한 락킹 방지

Clojure에서 에이전트는 변경 가능한 상태를 처리하고 변경을 동기화하는데 사용되는 강력한 도구입니다. 에이전트는 STM(Software Transactional Memory)을 기반으로 하여, 동시성을 관리하고 race condition을 피하기 위한 방식으로 작동합니다.

때로는 에이전트의 동시성 제어 메커니즘에 대한 정확한 이해 없이 코드를 작성하는 경우 무분별한 락킹이 발생할 수 있습니다.

문제

예를 들어, 다음과 같은 Clojure 코드를 고려해 봅시다.

(def score (agent 0))

(defn update-score [amount]
  (send score + amount))

(update-score 10)

위의 코드는 스레드 안전한 방식으로 score를 증가시키는 것처럼 보입니다. 그러나 send 함수는 비동기적으로 실행되며, 각 send 호출이 동시에 실행될 수 있습니다. 이는 결과적으로 score가 락되지 않는 순간에 여러번 업데이트될 수 있음을 의미합니다.

해결책

무분별한 락킹을 피하기 위해 에이전트를 사용할 때에는 send보다는 send-off를 사용하는 것이 좋습니다. send-off는 별도의 스레드 풀에서 에이전트 작업을 처리함으로써, 기본 스레드 풀을 블록시키지 않으며 각 작업마다 동시성을 보장합니다. 따라서 다음과 같이 코드를 수정할 수 있습니다.

(def score (agent 0))

(defn update-score [amount]
  (send-off score + amount))

(update-score 10)

이를 통해 에이전트가 보다 효과적으로 동시성을 관리하고 락킹을 피하도록 할 수 있습니다.

또한, 에이전트를 사용할 때에는 코드를 작성하기 전에 에이전트의 동작 원리와 주의사항을 충분히 이해하는 것이 중요합니다.

결론

Clojure에서 에이전트를 사용할 때에는 무분별한 락킹을 방지하기 위해 send-off를 사용하고, 에이전트의 동작 원리와 주의사항에 대한 이해가 필요합니다. 이를 통해 안정적이고 효율적인 동시성 처리가 가능해집니다.

참고: Clojure 에이전트 문서