openlang

swap! 함수 안의 println

swap! 문서에는 함수가 여러 번 호출될 수 있으니 부수 효과가 없어야 한다고 적혀 있다. 그런데 실제 코드에는 그 안에서 로그를 찍는 경우가 여전히 있다.

(def hits (atom 0))

(defn record! [id]
  (swap! hits (fn [n]
                (println "counting" id)
                (inc n))))

아톰의 값은 어떤 경우에도 맞다. 커밋되는 시도는 하나뿐이기 때문이다. println은 그 커밋에 속하지 않는다. 두 스레드가 경쟁하면 진 쪽 시도는 이미 출력을 한 뒤에 다시 실행되고, 그래서 한 번의 호출에 줄이 두 번 찍힐 수 있다. dosync 안의 부수 효과와 같은 모양이고, 조정하는 장치가 없으니 오히려 더 쉽게 걸린다. 내가 쓰는 해법은 swap-vals!다. 이전 값과 새 값을 돌려주니 반환된 뒤에 로그를 남기면 된다.

이어지는 대화 1

서로의 근거를 따라
  1. 고유 링크

    사람들이 이걸 두는 다른 자리는 add-watch예요. 워치 함수는 변경이 반영된 뒤에 이전 상태와 새 상태를 받으니까 성공한 swap마다 한 번만 돌아요. 다만 swap을 한 그 스레드에서 호출되니까, 워치가 느리면 호출하는 쪽이 전부 느려져요. println이면 상관없지만 네트워크 호출이면 얘기가 달라요.

같은 질문의 다른 갈래

  1. Isolate.run이 Loader를 통째로 데려갔어요

    큰 JSON 디코딩을 Isolate.run으로 메인 isolate 밖에 빼 봤는데, 빨라지기는커녕 보낼 수 없는 객체라는 오류가 났어요. 디코딩 자체는 문제가 없었고 클로저가 문제였어요. _decode가 인스턴스 메서드라서…

    답글 2dart
  2. 컨텍스트 취소 뒤 결과 전송에서 멈춘 워커들

    단순한 건데 생각보다 오래 붙잡고 있었어요. 워커 여덟 개짜리 풀이 jobs에서 작업을 읽고, 버퍼 없는 results에 결과를 써요. 소비자는 results를 루프로 읽다가 첫 에러가 나면 ctx.Done()으로 돌아가요.…

    답글 8go
  3. fetch 하나가 실패할 때의 asyncio.TaskGroup

    언어끼리 동시성을 비교할 때는 보통 문법부터 봐요. 저는 뭔가 실패했을 때 계산에 무엇이 필요한지부터 보고 싶어요. 작은 Python 애플리케이션이 측정값과 가중치를 동시에 가져와서 점수 하나로 합쳐요. 그런데 fetch 하…