Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 20 additions & 17 deletions streams/shared/src/main/scala/zio/stream/ZStream.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4523,37 +4523,40 @@ object ZStream extends ZStreamPlatformSpecificConstructors {
def fromIteratorSucceed[A](iterator: => Iterator[A], maxChunkSize: => Int = DefaultChunkSize)(implicit
trace: Trace
): ZStream[Any, Nothing, A] = {

def writeOneByOne(iterator: Iterator[A]): ZChannel[Any, Any, Any, Any, Nothing, Chunk[A], Any] =
if (iterator.hasNext)
ZChannel.write(Chunk.single(iterator.next())) *> writeOneByOne(iterator)
else
ZChannel.unit

def writeChunks(iterator: Iterator[A]): ZChannel[Any, Any, Any, Any, Nothing, Chunk[A], Any] =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT the main optimization is to use val builder = ChunkBuilder.make[A](maxChunkSize) is that right?

If that's the case maybe keep this method and make the optimization within it just to keep blame / git history with as few changes as possible (which makes it easier to track potential bugs)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! I minimized the changes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kyri-petrou , I think there's another small gain here by eliminating intermediate lambdas/thunks. basic idea: have one ZChannel.succeed evaluating chunk size and creating the builder if needed, then calling either writeOneByOne or writeChunks - both taking eager parameters and potentially running the first steps under the top level thunk (line 4553 in the original code)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eyalfa I'm not sure I understand your suggestion. Can you provide a code example?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what @eyalfa is saying is that the optimisation is not only val builder = ChunkBuilder.make[A](maxChunkSize) but also to eliminate the ZChannel.succeed which was used in writeChunks but wasn't required as the execution was already suspended with ZChannel.suspend

ZChannel.succeed(ChunkBuilder.make[A]()).flatMap { builder =>
def loop(iterator: Iterator[A]): ZChannel[Any, Any, Any, Any, Nothing, Chunk[A], Any] = {
builder.clear()
var count = 0
while (count < maxChunkSize && iterator.hasNext) {
builder += iterator.next()
count += 1
}
if (count > 0)
ZChannel.write(builder.result()) *> loop(iterator)
else
ZChannel.unit
def writeChunks(iterator: Iterator[A], maxChunkSize0: Int): ZChannel[Any, Any, Any, Any, Nothing, Chunk[A], Any] = {
val builder = ChunkBuilder.make[A](maxChunkSize0)

def loop(iterator: Iterator[A]): ZChannel[Any, Any, Any, Any, Nothing, Chunk[A], Any] = {
builder.clear()
var count = 0
while (count < maxChunkSize0 && iterator.hasNext) {
builder += iterator.next()
count += 1
}

loop(iterator)
if (count > 0)
ZChannel.write(builder.result()) *> loop(iterator)
else
ZChannel.unit
}

loop(iterator)
}

ZStream.fromChannel {
ZChannel.suspend {
if (maxChunkSize == 1)
val maxChunkSize0 = maxChunkSize

if (maxChunkSize0 == 1)
writeOneByOne(iterator)
else
writeChunks(iterator)
writeChunks(iterator, maxChunkSize0)
}
}
}
Expand Down