Reputation: 695
I have a for comprehension like this using an image library that supports concurrent operations https://github.com/sksamuel/scrimage :
for (
file <- myDirectory.listFiles;
image <- AsyncImage(file);
scaled <- image.scale(0.5)
// possibly more ops here?
)
{
scaled.writer(Format.PNG).write(new File(dirOutput + file.getName))
}
here is the definition for write()
:
def write(out: OutputStream)(implicit executionContext: ExecutionContext): Future[Unit] = Future {
writer.write(out)
}
What I want to do is wait until all my images in my directory finish resizing before my program shutdowns. From what I gleaned from other posts on SO is to basically stuff all these Futures into a list of Futures and and use Await
for that to finish... Can anyone help me out here?
Upvotes: 2
Views: 1991
Reputation: 14404
The problem you are encountering is that you are mixing two different monadic comprehensions, i.e. listFiles
returns a List[File]
while image.scale
returns a Future[Image]
. While both can be used in a for-comprehension, they cannot be mixed. Also, image <- AsyncImage(file)
should be an assignment, since it just returns an instance:
// start the scaling operations (this is a List comprehension)
val scaleOps: List[Future[Unit]] = for {
file <- myDirectory.listFiles
image = AsyncImage(file)
// Now transform the image into a Future[Unit] with a nested Future comprehension
ops = for {
scaled <- image.scale(0.5)
written <- scaled.writer(Format.PNG).write(new File(dirOutput + file.getName))
} yield { written }
} yield { ops }
// collect and await the results
Await.result(Future.sequence(scaleOps), 10 minutes)
In the outer comprehension <-
always produces an item from a List
and yield
returns the final list.
In the inner comprehension <-
always produces the value of the Future
, allowing you to use it as input for another call producing a Future
, hence producing a Future[Unit]
out of the image
.
Upvotes: 2