我使用akka-streams api编写了一个简单的流,假设它将处理我的源代码,但不幸的是它没有。我确信我的来源做错了。我只是创建了一个迭代器,它生成了大量的元素,假设它无关紧要,因为akka-streams api会处理背压。我做错了什么,这是我的迭代器。
def createData(args: Array[String]): Iterator[TimeSeriesValue] = {
var data = new ListBuffer[TimeSeriesValue]()
for (i <- 1 to range) {
sessionId = UUID.randomUUID()
for (j <- 1 to countersPerSession) {
time = DateTime.now()
keyName = s"Encoder-${sessionId.toString}-Controller.CaptureFrameCount.$j"
for (k <- 1 to snapShotCount) {
time = time.plusSeconds(2)
fValue = new Random().nextLong()
data += TimeSeriesValue(sessionId, keyName, time, fValue)
totalRows += 1
}
}
}
data.iterator
}
答案 0 :(得分:2)
问题主要出在
行data += TimeSeriesValue(sessionId, keyName, time, fValue)
您不断向ListBuffer
添加“非常多的元素”。这会扼杀你所有的RAM。 data.iterator
行只是将一个巨大的ListBuffer blob包装在一个迭代器中,一次提供一个元素,它基本上只是一个强制转换。
你的假设是“因为...背压无关紧要”,部分原因是akka Stream会反应性地处理TimeSeriesValue
值,但是你甚至在得到之前就会创建大量的值到Source构造函数。
如果你希望这个迭代器是“懒惰的”,即只在需要时产生值而不消耗内存,那么进行以下修改(注意:我拆开了代码以使其更具可读性):
def createTimeSeries(startTime: Time, snapShotCount : Int, sessionId : UUID, keyName : String) =
Iterator.range(1, snapShotCount)
.map(_ * 2)
.map(startTime plusSeconds _)
.map(t => TimeSeriesValue(sessionId, keyName, t, ThreadLocalRandom.current().nextLong()))
def sessionGenerator(countersPerSession : Int, sessionID : UUID) =
Iterator.range(1, countersPerSession)
.map(j => s"Encoder-${sessionId.toString}-Controller.CaptureFrameCount.$j")
.flatMap { keyName =>
createTimeSeries(DateTime.now(), snapShotCount, sessionID, keyName)
}
object UUIDIterator extends Iterator[UUID] {
def hasNext : Boolean = true
def next() : UUID = UUID.randomUUID()
}
def iterateOverIDs(range : Int) =
UUIDIterator.take(range)
.flatMap(sessionID => sessionGenerator(countersPerSession, sessionID))
上述每个函数都返回一个迭代器。因此,调用iterateOverIDs
应该是即时的,因为没有立即完成工作并且正在消耗de mimimis内存。然后可以将此迭代器传递到您的Stream ...