>
> What you said holds for reduction but not necessarily a parallel fold (see 
> clojure.core.reducers/fold).
>

Exactly, and that's why stateful transducers are explicitly forbidden in 
fold and in core.async pipeline functions.
This is not related to memory visibility, this is due to the fact that 
stateful transducers force the reducing process to be sequential.
Does it make any sense to parallelize map-indexed ? partition-all ? dedupe ?


These kinds of failures are inherently difficult to reproduce unless the 
> code is in production and you're on vacation. ;)
>

Couldn't agree more. However, we're all clever people and the Java Memory 
Model is not magic :) 


Léo, I definitely agree that you can use unsynchronized mutable stateful 
> transducers *as long as you can guarantee they'll be used only in 
> single-threaded contexts.* 


The problem is at a lower level. The memory model of the JVM 
> doesn't guarantee that changes to an unsynchronized non-volatile reference 
> are visible to other threads.
>
 
The Java Memory Model allows using unsynchronized variables to share data 
across threads as long as a memory barrier is set between the writer and 
the reader. For example, in the case of core.async, the channel lock sets a 
barrier, and there is also (redundant) barriers for each volatile inside 
transducers.


A transducing process could apply each step of the transduce using a thread 
> from a pool and also not use a memory barrier

 

> Transducers included in core cannot make the assumption that they will 
> only be used that way.
>

Yes, that makes sense that you can't make that assumption. 

 
This is the key point : what assumptions a transducer can make ?
In my opinion, it is reasonable for a stateful transducer to assume that 
the transducing context will fulfill the contract of "always passing the 
result of step n to the first argument of step n+1".
This assumption is powerful because it guarantees that there will always be 
a memory barrier between two successive steps.
Proof (reductio ad absurdum) : without a memory barrier, the result of the 
step n wouldn't be visible to the (potentially different) thread performing 
the step n+1.
So here is my question to the language designers : is it reasonable to 
assume that ?
If yes, that means it's ok to use unsynchronized variables in stateful 
transducers as long as they stay local.
If no, that means we'll use synchronization in all stateful transducers, 
with an obvious performance penalty and a benefit that remains unclear.



On Monday, April 10, 2017 at 7:34:39 PM UTC+2, Alexander Gunnarson wrote:
>
> Yes, that makes sense that you can't make that assumption. You'd have to 
> create something like what I was discussing above:
>
> (defn map-indexed-transducer-base [f box-mutable inc-mutable]
>   (fn [rf]
>     (let [i (box-mutable -1)]
>       (fn
>         ([] (rf))
>         ([result] (rf result))
>         ([result input]
>           (rf result (f (inc-mutable i) input)))))))
>
> ;; this is the version that Léo would want
> (defn map-indexed-transducer-single-threaded [f]
>   (map-indexed-transducer-base f unsynchronized-mutable-long! 
> #(unsynchronized-mutable-swap! 
> % inc))
>
> ;; this is the version included in clojure.core
> (defn map-indexed-transducer-sequentially-accessed-by-different-threads [f
> ]
>   (map-indexed-transducer-base f volatile! #(vswap! % inc))
>
> ;; this works with `fold` and gives you all the indices at least, but in a 
> nondeterministic order
> (defn map-indexed-transducer-concurrently-accessed-by-different-threads [f
> ]
>   (map-indexed-transducer-base f atom #(swap! % inc)) ; or an AtomicLong 
> variant
>
> On Monday, April 10, 2017 at 1:06:14 PM UTC-4, Alex Miller wrote:
>>
>>
>> On Monday, April 10, 2017 at 11:48:41 AM UTC-5, Alexander Gunnarson wrote:
>>>
>>> Léo, I definitely agree that you can use unsynchronized mutable stateful 
>>> transducers *as long as you can guarantee they'll be used only in 
>>> single-threaded contexts. *
>>>
>>
>> Transducers included in core cannot make the assumption that they will 
>> only be used that way. (But you may be able to guarantee that with your 
>> own.)
>>
>>

-- 
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.

Reply via email to