On Mon, Mar 23, 2009 at 11:19 AM, Cosmin Stejerean <cstejer...@gmail.com> wrote:
>
> On Sun, Mar 22, 2009 at 9:12 PM, Mark Volkmann <r.mark.volkm...@gmail.com>
> wrote:
>>
>> I'm trying to understand the degree to which Clojure's STM provides
>> more concurrency than Java's blocking approach. I know it's difficult
>> to make generalizations and that specific applications need to be
>> measured, but I'll give it a go anyway.
>>
>> Clearly using STM (dosync with Refs) makes code easier to write than
>> using Java synchronization because you don't have to determine up
>> front which objects need to be locked. In the Clojure approach,
>> nothing is locked. Changes in the transaction happen to in-transaction
>> values and there is only a small amount of blocking that occurs at the
>> end of the transaction when changes are being committed. Score one for
>> Clojure!
>>
>> What concerns me though is how often the work done in two transactions
>> running in separate threads turns out to be useful work. It seems that
>> it will typically be the case that when two concurrent transactions
>> access the same Refs, one of them will commit and the other will
>> retry. The retry will discard the in-transaction changes that were
>> made to the Refs, essentially rendering the work it did of no value.
>> So there was increased concurrency, but not useful concurrency.
>
> In the case where two transactions need to modify the same Ref they
> definitely to be serialized, either by explicitly using locks in Java, or by
> letting Clojure automatically retry one of them. In either case it about the
> same thing happens. Transaction A starts and finishes, then Transaction B
> starts and finishes.

I don't think the same thing happens. In the case of Clojure, both
transaction A and B start. Suppose A finishes first and commits. Then
transaction B retries, finishes and commits. That's what I was
referring to as non-useful work. I'm not saying it's the wrong
approach, but it is different.

>> Of course there is a chance that the transaction contains some
>> conditional logic that makes it so the Refs to be accessed aren't
>> always the same, but my speculation is that that's are rare
>> occurrence. It's probably more typical that a transaction always
>> accesses the same set of Refs every time it executes.
>
> Which Refs your transactions modify will depend heavily based on the
> specific application you are working on. For example I can imagine that an
> application dealing with bank accounts and transferring money between them
> the probability of two transactions concurrently hitting the same account is
> pretty low. In other applications where a lot of transactions modify the
> same global state the chances of conflicts are much higher.

Agreed.

>> This makes it seem that Java's locking approach isn't so bad. Well,
>> it's bad that I have to identify the objects to lock, but it's good
>> that it doesn't waste cycles doing work that will just be thrown away.
>
> There's a reason concurrent programming is notoriously hard in most
> languages, because it takes a lot of effort and skill to get right. Between
> having to correctly identify which objects need to be locked and trying to
> avoid deadlocks dealing with explicit locks can be pretty messy and
> dangerous. That doesn't mean Java's approach is bad, after all the internals
> of Clojure are implemented using Java locks. But explicit management of
> locks is often too low level and unnecessarily complex, and Clojure provides
> a higher level way of dealing with concurrency that makes it easier and
> safer to work with most of the time.

I agree that Clojure makes the programming much easier, but is there a
downside? Maybe the downside is performance. If I found out that a
particular transaction was commonly being retried many times, is that
a sign that I need to write the code differently? How would I find out
that was happening? I know I could insert my own code to track that,
but it seems like this may be a commonly needed tool for Clojure to
detect excessive conflicts/retries in transactions. Maybe we could set
a special variable like *track-retries* that would cause Clojure to
produce a text file that describes all the transaction retries that
occurred in a particular run of an application. If such a tool isn't
needed or wouldn't be useful, I'd like to understand why.

-- 
R. Mark Volkmann
Object Computing, Inc.

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

Reply via email to