2014-10-13 3 views
1

처음 Monger에서 데이터베이스 참조를 가져 오는 get-database 함수를 구현하려고합니다. 원자에서 값을 기억하고 후속 호출에서 직접 반환합니다. 나의 현재 코드는 다음과 같습니다compare-and-set을 사용한 지연 평가

(def database (atom nil)) 

(defn get-database 
    [] 
    (compare-and-set! database nil 
    (let [db (:db (mg/connect-via-uri (System/getenv "MONGOLAB_URI")))] db)) 
    @database) 

문제는 let 절은 거짓 경우에도 compare-and-set! 수익률을 평가하는 것 같다 (즉 databasenil하지 않습니다). 느슨하게 평가할 수있는 방법이있어 Monger 연결을 검색하는 페널티가 발생하지 않거나 근본적으로 잘못된 방법일까요?

답변

4

여기서 문제는 compare-and-set!이 함수이므로 평가할 때 앞에있는 모든 매개 변수를 평가하면 전에 함수가 호출됩니다.

내가 캐싱 및 약간의 비용이 드는 계산 값을 다시 사용하는 사용 사례에 대해 수행 일반적인 접근 방식은 함께 delay A :

는 표현의 몸을 취득 해하는 지연 개체를 얻을 수 은 강제로 처음으로 (force 또는 deref/@를 사용하여) 본문을 호출하고 은 결과를 캐시하고 모든 후속 강제 호출 호출시이를 반환합니다. 또한보십시오 - 깨달았습니까? 귀하의 경우에는

:

(def database (delay (:db (mg/connect-via-uri (System/getenv "MONGOLAB_URI"))))) 

지금 당신은 @database 데이터베이스에 대한 참조를 얻기 위해 원하는 시간을 말할 수 있고, 연결이 코드가 실제로 지연이 발생 처음 초기화 얻을 것이다 역 참조 될 수 있습니다. 원할 경우 get-database 함수 내에서 지연을 역 참조하기 위해 호출을 래핑 할 수 있지만 필요하지는 않습니다.

+0

니스. 그래서 나는이 경우에'database'를 원자로 만드는 것은 무리가 있다고 생각합니다. 지연을 사용하면 경쟁 조건이 발생하지 않을 것이라고 보장합니까? –

+0

수정. 지연 구현은 스레드로부터 안전하며 본문이 한 번만 실행되도록합니다. 본문이 실행되는 동안 다른 스레드에서 지연을 역 참조하려고하면 완료 될 때까지 차단됩니다. – Alex

+0

이 질문은 별개의 질문 일지 모르지만 지연 동시 업데이트에 대해서는 아직 명확하지 않습니다. 역 참조가 된 후 지연 값을 변경하는 것이 좋을까요? 그렇다면 왜 원자는'swap! '(또는 다른 함수)을 사용하여 업데이트되어야하지만 딜레이에는 동등한 함수가 없다. –