My guess is that partition-all and partition use non-volatile references because none of the built-in stuff will return control back to the caller at a finer resolution than output value (AFAIK). That's why take needs volatile but partition-all doesn't (because for take the state persists between output values). It does mean that new transducing contexts would need to synchronize though - which core.async does through mutexes.
On Sunday, April 9, 2017 at 8:47:25 AM UTC-5, tbc++ wrote: > > The volatile! is needed for the case where a transducer is only used by > one thread at a time, but the thread executing the transducer may change > from one call to the next. This happens fairly often with core.async. If > you used a non-atomic, non-volatile mutable field, the JVM would be free to > perform several optimizations (like keeping the local in a CPU register) > that would cause the value to not properly propagate to other threads in > the case of a context switch. Using volatile! tells the JVM to flush all > writes to this field by the time the next memory barrier rolls around. It > also tells the JVM to make sure it doesn't cache the reads to this field > across memory barriers. > > It's a tricky subject, and one that's really hard to test, and frankly I > probably got some of the specifics wrong in that last paragraph, but that's > the general idea of why transducers use volatile!. > > Timothy > > On Sun, Apr 9, 2017 at 12:49 AM, Alexander Gunnarson < > alexander...@gmail.com <javascript:>> wrote: > >> EDIT: Transducers are actually not safe in `fold` contexts as I thought: >> >> (let [f (fn [i x] (println (str "i " i " " (Thread/currentThread))) >> (flush) x) >> r-map-indexed #(r/folder %2 (map-indexed %1))] >> (->> [6 7 8 9 10] >> (r-map-indexed f) >> (r/fold 1 (fn ([] (vector)) ([x] x) ([a b] (into a b))) conj))) >> >> Produces: >> >> i 0 Thread[ForkJoinPool-1-worker-2,5,main] >> i 2 Thread[ForkJoinPool-1-worker-1,5,main] >> i 3 Thread[ForkJoinPool-1-worker-1,5,main] >> i 4 Thread[ForkJoinPool-1-worker-1,5,main] >> i 1 Thread[ForkJoinPool-1-worker-3,5,main] >> >> So you would have to be careful to e.g. create different `map-indexed` >> transducers for single-threaded (e.g. `unsynchronized-mutable` box) and >> multi-threaded (e.g. `atom` box) contexts. >> >> On Sunday, April 9, 2017 at 2:10:06 AM UTC-4, Alexander Gunnarson wrote: >>> >>> I was wondering the same thing, shintotomoe. This thread >>> <https://groups.google.com/forum/#!topic/clojure/CjxK7xEsOKQ> talks >>> about it as well. I think it's safe to assume that since `ArrayList` uses >>> unsynchronized mutability internally (a quick review of the GrepCode >>> entry for `ArrayList` confirms this >>> <http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/ArrayList.java>), >>> >>> then we can rest assured that a `volatile` box as opposed to a totally >>> unsynchronized mutable variable is unnecessary, even in the context of >>> `fold`. After all, `reduce` (and by extension, `transduce`) is only ever >>> going to be single-threaded unless the data structure in question >>> unexpectedly implements a multithreaded reduce, which should never happen >>> (and if it does, you likely have bigger problems). To be honest, I'm not >>> sure why `volatile` is used in transducers instead of e.g. an >>> `unsynchronized-mutable` box. There may be a good reason, but I'm not >>> seeing it immediately. I'd love to learn. >>> >>> On Thursday, January 1, 2015 at 10:36:13 PM UTC-5, shintotomoe wrote: >>>> >>>> Thank you for the superfast response. I take it implementing your own >>>> transducing process is not something you would usually do unless you have >>>> a >>>> unique use case (my own use case being already implemented by chan taking >>>> a >>>> transducer). >>>> >>>> Still, I was wondering about the use of ArrayList in partition-all, and >>>> the recommendation to use volatiles inside transducers, which seem at >>>> odds. >>>> It seems we don't need to implement transducers in a thread-safe way. Is >>>> that correct? >>>> >>>> On Friday, January 2, 2015 12:58:51 PM UTC+11, tbc++ wrote: >>>>> >>>>> Core.async already has pipeline, pipeline-blocking and pipeline-async. >>>>> In addition you can use a transducer inside a channel. Use those instead. >>>>> >>>>> Timothy >>>>> >>>>> On Thu, Jan 1, 2015 at 6:55 PM, shintotomoe <tste...@atlassian.com> >>>>> wrote: >>>>> >>>>>> I was wondering how to apply a transducer inside a go process. What >>>>>> I've so far is the following >>>>>> >>>>>> (defn pipe-xform [in-ch out-ch xform] >>>>>> (let [tr >>>>>> (let [tr (xform (fn >>>>>> ([result] result) >>>>>> ([result input] (conj! result input))))] >>>>>> (fn >>>>>> ([] (locking tr (persistent! (tr (transient []))))) >>>>>> ([input] (locking tr (persistent! (tr (transient []) >>>>>> input))))))] >>>>>> (go-loop [] >>>>>> (if-some [value (<! in-ch)] >>>>>> (do (doseq [v (tr value)] >>>>>> (>! out-ch v)) >>>>>> (recur)) >>>>>> (do (doseq [v (tr)] >>>>>> (>! out-ch v)) >>>>>> (close! out-ch)))))) >>>>>> >>>>>> Now, I could just do >>>>>> >>>>>> (let [xf-ch (chan 1 xform)] >>>>>> (pipe in-ch xf-ch) >>>>>> (pipe xf-ch out-ch) >>>>>> >>>>>> >>>>>> Or just redesign my code so that I can create in-ch or out-ch with >>>>>> the transducer directly, but I was wondering whether there are any >>>>>> obvious >>>>>> flaws with the pipe-xform implementation. >>>>>> >>>>>> In particular, I was wondering about the locking. At first I was >>>>>> under the impression that transducers are thread-safe due to the use of >>>>>> volatiles, but looking at the partition-all transducer, which uses an >>>>>> ArrayList for its state, It appears that's not the case. >>>>>> >>>>>> Any feedback greatly appreciated. >>>>>> >>>>>> -- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "Clojure" group. >>>>>> To post to this group, send email to clo...@googlegroups.com >>>>>> Note that posts from new members are moderated - please be patient >>>>>> with your first post. >>>>>> To unsubscribe from this group, send email to >>>>>> clojure+u...@googlegroups.com >>>>>> For more options, visit this group at >>>>>> http://groups.google.com/group/clojure?hl=en >>>>>> --- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "Clojure" group. >>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>> send an email to clojure+u...@googlegroups.com. >>>>>> For more options, visit https://groups.google.com/d/optout. >>>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> “One of the main causes of the fall of the Roman Empire was >>>>> that–lacking zero–they had no way to indicate successful termination of >>>>> their C programs.” >>>>> (Robert Firth) >>>>> >>>> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clo...@googlegroups.com >> <javascript:> >> Note that posts from new members are moderated - please be patient with >> your first post. >> To unsubscribe from this group, send email to >> clojure+u...@googlegroups.com <javascript:> >> For more options, visit this group at >> http://groups.google.com/group/clojure?hl=en >> --- >> You received this message because you are subscribed to the Google Groups >> "Clojure" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to clojure+u...@googlegroups.com <javascript:>. >> For more options, visit https://groups.google.com/d/optout. >> > > > > -- > “One of the main causes of the fall of the Roman Empire was that–lacking > zero–they had no way to indicate successful termination of their C > programs.” > (Robert Firth) > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.