2011-03-30 2 views
2

그래서 congomongo (끝 근처의 가져 오기 기능)를 사용하여 mongodb 컬렉션에서 일부 문서를 가져옵니다. 가져 오기 호출을 통해 옵션을 전달하려면 (posts :limit 1)과 같은 것을 수행하고 {:limit 1}을 가져 와서 가져 오도록 할 수 있습니다. clojure.core/memoize으로 이해할 수있는 캐시를 재설정 할 수 있기를 원하기 때문에 손으로 말한 "memoization"을 @posts과 함께 수행하고 있습니다.더 많은 관용적 인 멍청한 코드를 만들 수 있도록 도와주세요

지금 보았을 때 문제는 (fetch :posts options) 호출이 중요하지 않으며, dosync가 트랜잭션을 다시 시도해야한다면 실제로 데이터 저장소를 해머하지 않을 것입니다. 나는 총 clojure/fp 멍청한 놈이지만, 나는 그 문제를 해결하는 방법을 모르겠다. 또한, 내가 멍청이이기 때문에, 내가 여기있는 다른 일을하면 너는 싫증이 나고, 나는 이것을 올바르게 쓰는 방법을 찾고 싶다.

나에게 잘 숙어의 Clojure의 모양
(def posts (ref nil)) 
(defn reset-posts [] (dosync alter posts nil)) 

(defn fetch-posts [& options] 
    (let [options (apply array-map options)] 
    (or @posts 
     (dosync alter posts (fetch :posts options))))) 
+1

@cdereview.stackexchange.com –

+0

@Duncan Bayne : 그 존재를 알지 못 했어, 고마워 :) –

답변

6

! reset-posts에서

user=> (def posts (ref nil)) 
#'user/posts 
user=> (dosync (ref-set posts [1 2 3 4 5])) 
[1 2 3 4 5] 
user=> @posts 
[1 2 3 4 5] 
user=> (dosync alter posts nil) 
nil 
user=> @posts 
[1 2 3 4 5] 

, 당신은 아마 (dosync (ref-set posts nil))을 원하고 fetch-posts에서, 구문 수정 (dosync (ref-set posts (fetch :posts options)))이 될 것입니다.

그러나 경쟁 조건이 fetch-posts인데, 이는 check-then-act입니다. 그렇게 큰 거래는 아닐 수도 있습니다. 누가 fetch-posts을 사용하는지 확실하지 않지만 or @posts 비트를 트랜잭션 내부로 이동 시키면 2 개의 동시 트랜잭션이 모두 변경을 끝내는 상황을 피할 수 있습니다.

캐시 솔루션이 대부분을 피할지라도 fetch-posts의 재시도 관련 문제는 발생할 수 있습니다. 나는 잠그지 않고 그 주위에 방법이 있는지 확신하지 못한다. 일반적으로 트랜잭션에서 입출력을 처리 할 때는 에이전트에게 전달하지만 트랜잭션의 성공 여부는 fetch의 반환 값에 따라 달라 지므로 어떻게 작동하는지 명확하지 않습니다.

+0

조언을 주셔서 감사합니다. :) 몇 가지 독서를했는데 ref- set과 alter는 변수가 값을 설정하는 함수를 실행하고, ref-set은 전달하는 값으로 설정하므로 param이 의미가 없으므로 아무 것도하지 않습니다. –

+0

그래. 또 다른 중요한 차이점은'dosync'는 평가할 양식을 취한다는 것인데, 원래 예제에서'alter'는 실제로'post'와'nil'처럼 함수로 평가 된 것입니다. '@ posts'가 맵으로 시작되면'(dosync (alter posts assoc : foo "bar"))'와 같은 것이 작동 할 것입니다. – trptcolin

1

, 그나마 자신에 너무 열심히 일 : 나는 당신의 트랜잭션 블록 ((dosync alter ...) 당신은 어떻게 생각하십니까 확신 아니에요

1

그래서 시간이 지날 때 메모리를 날려 버릴 수 없기 때문에 ref를 소개합니다. 페치 포스트 주변에서 메모를 사용하면 조만간이 문제가 발생할 수 있습니다.

아마도 대체 방법을 시도해 볼 수 있습니다. 가져온 글을 메모가없는 '순수한'문서로 만들 수 있습니다. 이 시나리오를 통해 OutOfMemoryExceptions을 두려워하지 않고도 누군가가 fetch-posts를 블라인드없이 호출 할 수 있습니다. 실제로, 어떤 경우에는 호출 코드의 로컬에서 "값을 캐시하는 것"으로 충분할 수도 있습니다.

하지만 여기서 이야기가 끝나지 않거나 대답 할 시간이 없었을 것입니다. clojure.core/binding을 사용하여 가져 오기 작업을 리빌드하여 "현지화 된 시간에 맞게"메모를 작성할 수 있습니다. 그때부터 호출 스택의 같은 스레드에있는 모든 코드는 묶여진 memoized fetch-posts로부터 이익을 얻습니다. clojure 1.3 alpha를 사용하는 경우 : 동적 메타 데이터를 통해 fetch-posts var를 명시 적으로 rebindable로 선언해야합니다.

;; most simple definition 
(defn ^:dynamic fetch-posts [& options] 
    (let [options (apply array-map options)] 
    (fetch :posts options))) 

;; a la carte caching by the calling code (lexically scoped) 
(let [posts (apply fetch-posts options)] ...) 

;; a la carte caching by the calling code (dynamically scoped) 
(binding [fetch-posts (memoize fetch-posts)] ...) 

내 마지막 추측은 옵션 서열이 될 것 키로 게시물을 색인하여 원래 버전의 글에서 "memoize",에, 권리 싶어한다는 것입니까? 코드가 맞지 않을 수도 있습니다. (또는 fetch-posts가 항상 같은 args를 가지고 계속해서 호출된다는 가정을했다.)

또 다른 생각.단지 그것을 전무 때 이루어집니다 게시물에 대한 쓰기 액세스를 직렬화하고 가져 오기에 대한 호출을 보장하기 위해 에이전트를 사용

(def posts (agent nil)) 

    (defn reset-posts [] (send posts (constantly nil))) 

    (defn fetch-posts [& options] 
     (let [options (apply array-map options)] 
     (send-off posts #(or % (fetch :posts options))) 
     (await-for (Long/MAX_VALUE) posts) 
     @posts)) 
+0

그래, 내가 일종의 "일종의"상태 였을 때 나는이 질문을 올렸고, 그 결과를 좀 더 빨리 캐쉬해야한다는 것을 깨달았다. 당신이 제공 한 첫 번째 예제는 아마도 내가 취할 접근법이지만, 에이전트 예제 덕분에 더 많이 내가 그것을 사랑하는 clojure 동시성 모델에 대해 배울 수 있습니다. –

1

dosyncdelay을 사용하는 것 이외의 다양한 계산을 이동하는 것이 유용 할 수있는 또 다른 방법입니다.

(defn fetch-posts 
    [& options] 
    @(dosync (or @posts (ref-set posts (delay (apply fetch :posts options)))))) 

또한 당신이 dosync 이외의 심판에 액세스하고 나중에 dosync에서이 값을 기준으로 수정하기 때문에 원래의 코드가 하지 스레드 안전 있습니다. 그러나 값은 derefdosync 사이에서 이미 변경되었을 수 있습니다. 예 : 다른 스레드는 fetch-posts을 병렬로 호출합니다.

신뢰할 수있는 에이전트를 읽을 수 없기 때문에 에이전트 접근 방식도 의심 스럽습니다. 얻은 값은 일관성이 있지만 액세스가 동기화되지 않습니다. Laurent의 예를 들어 보자. await-forderef 사이에 다른 스레드가 이미 reset-posts을 호출하고 게시 데이터 대신 nil이 표시 될 수 있습니다. 이 예에서는 아마도 a) 멀리 가져 왔고 b) 어쨌든 고려해야 할 경우 일 수 있습니다. 그러나 더 중요한 코드에서 미묘한 경쟁 조건이 발생하는 다른 사용 사례가있을 수 있습니다.

tl; dr : 당신이하는 일에 조심하십시오. Clojure는 마술처럼 스레드로부터 안전하지는 않습니다. 솔루션에 대한 철저한 이유와 그 의미를 알아야합니다.

+0

사실, 대리인과 함께 가져 오기 게시물 내에 경쟁 조건이 있습니다 .-( –

관련 문제