我有这样的代码
var ls = src.iter.toList
src.iter = ls.iterator
(这是我的迭代器包装器的复制构造函数的一部分),它读取源迭代器,并在下一行中将其设置回来。问题是,这两行必须是原子的(特别是如果你认为我改变了复制构造函数的来源 - 我不喜欢它,但很好......)。
我读过有关Actors但我看不到它们如何适合 - 它们看起来更像是一种异步执行机制。我已经阅读了Java解决方案并在Scala中使用它们,例如:http://naedyr.blogspot.com/2011/03/atomic-scala.html
我的问题是:Scala最常用的方法是什么?我不想为此使用一些重型火炮,而且我也不想使用一些外部资源。换句话说 - 看起来和感觉“正确”的东西。
我喜欢上面链接中提供的解决方案,因为这正是我所做的 - 交换引用。如果我理解正确,我只会保护那两行,而其他代码不需要改变!但我会等待明确的回答。
因为每个第N个问题,而不是回答我读“但你为什么要使用......”,这里: How to copy iterator in Scala?: - )
我需要复制迭代器(制作一个分支),这样的解决方案是我读到的最“正确”。问题是,它破坏了原始的迭代器。
锁
例如: http://www.ibm.com/developerworks/java/library/j-scala02049/index.html
我在这里看到的唯一问题是,我必须锁定这两行以及iter上的所有其他用法。现在这是次要的,但是当我添加一些代码时,很容易忘记添加额外的锁。
我不是说“不”,但我没有经验,所以我想从熟悉Scala的人那里得到答案,指出一个方向 - 哪种解决方案最适合这样的任务,并且长期-run。
不可变迭代器
虽然我很欣赏Paradigmatic的解释,但我不知道这种方法如何适合我的问题。问题是IteratorWrapper类必须包装迭代器 - 即原始迭代器应隐藏在类中(通常通过将其设为私有来完成)。 hasNext()和next()等方法也应该包装好。通常next()会改变对象的状态(迭代器),所以在不可变的IteratorWrapper的情况下,它应该返回新的IteratorWrapper和next()的状态(成功与否)。如果raw next()失败,另一个解决方案是返回NULL,无论如何,这使得使用这样的IteratorWrapper不是很方便。
更糟糕的是,仍然没有简单的方法来复制这样的IteratorWrapper。
所以要么我想念一些东西,要么实际上经典的方法使得一段代码原子化更清晰。因为所有负担都包含在类中,并且用户不必付出代价,因此IteratorWrapper处理数据(在这种情况下是原始迭代器)。
答案 0 :(得分:4)
例如,您可以在对象构造中将迭代器转换为List
。由于列表是不可变的,因此您可以安全地共享它们而无需锁定:
class IteratorWrapper[A]( iter: Iterator[A] ) {
val list = iter.toList
def iteratorCopy = list.iterator
}
这里,IteratorWrapper
也是不可变的。你可以安全地传递它。但是如果你真的需要更改包装的迭代器,你将需要更多要求更高的方法。例如,您可以:
Actor
澄清:我缺乏有关您的问题限制的信息。但这是我理解的方式。
多个线程必须同时遍历Iterator
。一种可能的方法是在将引用传递给线程之前复制它。但是,Scala实践旨在共享不需要复制的不可变对象。
使用复制策略,您可以编写如下内容:
//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 )
}
}
}
但是,实现线程安全的复制方法很困难(或很慢)。使用不变性的可能解决方案是:
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 )
}
}
}
制作人在施工时会拨打produceIterator
一次。它是不可变的,因为它的状态只是一个也是不可变的列表。 iteratorCopy
也是线程安全的,因为在创建副本时不会修改列表(因此多个线程可以同时遍历它而不必锁定)。
请注意,调用list.iterator
不会遍历列表。所以它不会以任何方式降低性能(而不是每次都真正复制迭代器)。