Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make atomic exchange -- Scala way?

Problem

I have such code

var ls = src.iter.toList
src.iter = ls.iterator

(this is part of copy constructor of my iterator-wrapper) which reads the source iterator, and in next line set it back. The problem is, those two lines have to be atomic (especially if you consider that I change the source of copy constructor -- I don't like it, but well...).

I've read about Actors but I don't see how they fit here -- they look more like a mechanism for asynchronous execution. I've read about Java solutions and using them in Scala, for example: http://naedyr.blogspot.com/2011/03/atomic-scala.html

My question is: what is the most Scala way to make some operations atomic? I don't want to use some heavy artillery for this, and also I would not like to use some external resources. In other words -- something that looks and feels "right".

I kind like the solution presented in the above link, because this is what I exactly do -- exchange references. And if I understand correctly, I would guard only those 2 lines, and other code does not have to be altered! But I will wait for definitive answer.

Background

Because every Nth question, instead of answer I read "but why do you use...", here: How to copy iterator in Scala? :-)

I need to copy iterator (make a fork) and such solution is the most "right" I read about. The problem is, it destroys the original iterator.

Solutions

Locks

For example here: http://www.ibm.com/developerworks/java/library/j-scala02049/index.html

The only problem I see here, that I have to put lock on those two lines, and every other usage on iter. It is minor thing now, but when I add some code, it is easy to forget to add additional lock.

I am not saying "no", but I have no experience, so I would like to get answer from someone who is familiar with Scala, to point a direction -- which solution is the best for such task, and in long-run.

Immutable iterator

While I appreciate the explanation by Paradigmatic, I don't see how such approach fits my problem. The thing is IteratorWrapper class has to wrap iterator -- i.e. raw iterator should be hidden within the class (usually it is done by making it private). Such methods as hasNext() and next() should be wrapped as well. Normally next() alters the state of the object (iterator) so in case of immutable IteratorWrapper it should return both new IteratorWrapper and status of next() (successful or not). Another solution would be returning NULL if raw next() fails, anyway, this makes using such IteratorWrapper not very handy.

Worse, there is still not easy way to copy such IteratorWrapper.

So either I miss something, or actually classic approach with making piece of code atomic is cleaner. Because all the burden is contained inside the class, and the user does not have to pay the price of they way IteratorWrapper handles the data (raw iterator in this case).

like image 488
greenoldman Avatar asked Oct 09 '22 17:10

greenoldman


1 Answers

Scala approach is to favor immutability whenever it is possible (and it's very often possible). Then you do not need anymore copy constructors, locks, mutex, etc.

For example, you can convert the iterator to a List at object construction. Since lists are immutable, you can safely share them without having to lock:

class IteratorWrapper[A]( iter: Iterator[A] ) {
  val list = iter.toList

  def iteratorCopy = list.iterator
}

Here, the IteratorWrapper is also immutable. You can safely pass it around. But if you really need to change the wrapped iterator, you will need more demanding approaches. For instance you could:

  1. Use locks
  2. Transform the wrapper into an Actor
  3. Use STM (akka or other implementations).

Clarifications: I lack information on your problem constraints. But here is how I understand it.

Several threads must traverse simultaneously an Iterator. A possible approach is to copy it before passing the reference to the threads. However, Scala practice aims at sharing immutable objects that do not need to be copied.

With the copy strategy, you would write something like:

//A single iterator producer
class Producer {
  val iterator: Iterator[Foo] = produceIterator(...)
}

//Several consumers, living on different threads
class Consumer( p: Producer ) {
  def consumeIterator = {
    val iteratorCopy = copy( p.iterator ) //BROKEN !!!
    while( iteratorCopy.hasNext ) {
      doSomething( iteratorCopy.next )
    } 
  }  
}

However, it is difficult (or slow) to implement a copy method which is thread-safe. A possible solution using immutability will be:

class Producer {
  val lst: List[Foo] = produceIterator(...).toList 
  def iteratorCopy = list.iterator
}

class Consumer( p: Producer ) {
  def consumeIterator = {
    val iteratorCopy = p.iteratorCopy 
    while( iteratorCopy.hasNext ) {
      doSomething( iteratorCopy.next )
    } 
  }  
}

The producer will call produceIterator once at construction. It it immutable because its state is only a list which is also immutable. The iteratorCopy is also thread-safe, because the list is not modified when creating the copy (so several thread can traverse it simultaneously without having to lock).

Note that calling list.iterator does not traverse the list. So it will not decrease performances in any way (as opposed to really copying the iterator each time).

like image 99
paradigmatic Avatar answered Oct 15 '22 11:10

paradigmatic