Scala 与Monix的扇入/扇出并发
我正在努力学习Scala并从中获得乐趣,但我遇到了这个经典问题。这让我想起了NodeJS早期的许多嵌套回调地狱 以下是我的psuedocode程序:Scala 与Monix的扇入/扇出并发,scala,monix,Scala,Monix,我正在努力学习Scala并从中获得乐趣,但我遇到了这个经典问题。这让我想起了NodeJS早期的许多嵌套回调地狱 以下是我的psuedocode程序: 获取S3存储桶列表的任务 任务1完成后,我想以十个一组的方式批处理bucket 每批: 获取每个桶的区域 筛选出不在区域中的桶 列出每个bucket中的所有对象 打印所有内容 在某一点上,我以类型结束:Task[Iterator[Task[List[Bucket]]]] 基本上: 外部任务是列出所有S3存储桶的初始步骤,而内部迭代器/task/li
Task[Iterator[Task[List[Bucket]]]]
基本上:
外部任务是列出所有S3存储桶的初始步骤,而内部迭代器/task/list则试图批处理返回列表的任务
我希望有某种方法可以删除/展平外部任务,从而访问迭代器[Task[List[Bucket]]]
当我尝试将我的处理分解为多个步骤时,深层嵌套会导致我执行许多嵌套映射。这是正确的做法还是有更好的方法来处理这种嵌套?在这种特殊情况下,我建议使用类似于FS2的方法,将Monix作为F:
import cats.implicits._
import monix.eval._, monix.execution._
import fs2._
// use your own types here
type BucketName = String
type BucketRegion = String
type S3Object = String
// use your own implementations as well
val fetchS3Buckets: Task[List[BucketName]] = Task(???)
val bucketRegion: BucketName => Task[BucketRegion] = _ => Task(???)
val listObject: BucketName => Task[List[S3Object]] = _ => Task(???)
Stream.evalSeq(fetchS3Buckets)
.parEvalMap(10) { name =>
// checking region, filtering and listing on batches of 10
bucketRegion(name).flatMap {
case "my-region" => listObject(name)
case _ => Task.pure(List.empty)
}
}
.foldMonoid // combines List[S3Object] together
.compile.lastOrError // turns into Task with result
.map(list => println(s"Result: $list"))
.onErrorHandle { case error: Throwable => println(error) }
.runToFuture // or however you handle it
下面的FS2使用cats.effect.IO或Monix任务,或者任何您想要的任务,只要它提供了cats效果类型类。它构建了一个漂亮的、功能强大的DSL来设计数据流,因此您可以使用无Akka流的反应流
这里有一个小问题,我们一次打印所有结果,如果结果超过内存的处理能力,这可能是一个坏主意-我们可以分批打印(不确定这是否是您想要的),或者将过滤和打印分开
Stream.evalSeq(fetchS3Buckets)
.parEvalMap(10) { name =>
bucketRegion(name).map(name -> _)
}
.collect { case (name, "my-region") => name }
.parEvalMap(10) { name =>
listObject(name).map(list => println(s"Result: $list"))
}
.compile
.drain
虽然在裸Monix中这一切都不是不可能的,但FS2使此类操作更易于编写和维护,因此您应该能够更轻松地实现流程。在这种特殊情况下,我建议使用类似FS2的Monix作为F:
import cats.implicits._
import monix.eval._, monix.execution._
import fs2._
// use your own types here
type BucketName = String
type BucketRegion = String
type S3Object = String
// use your own implementations as well
val fetchS3Buckets: Task[List[BucketName]] = Task(???)
val bucketRegion: BucketName => Task[BucketRegion] = _ => Task(???)
val listObject: BucketName => Task[List[S3Object]] = _ => Task(???)
Stream.evalSeq(fetchS3Buckets)
.parEvalMap(10) { name =>
// checking region, filtering and listing on batches of 10
bucketRegion(name).flatMap {
case "my-region" => listObject(name)
case _ => Task.pure(List.empty)
}
}
.foldMonoid // combines List[S3Object] together
.compile.lastOrError // turns into Task with result
.map(list => println(s"Result: $list"))
.onErrorHandle { case error: Throwable => println(error) }
.runToFuture // or however you handle it
下面的FS2使用cats.effect.IO或Monix任务,或者任何您想要的任务,只要它提供了cats效果类型类。它构建了一个漂亮的、功能强大的DSL来设计数据流,因此您可以使用无Akka流的反应流
这里有一个小问题,我们一次打印所有结果,如果结果超过内存的处理能力,这可能是一个坏主意-我们可以分批打印(不确定这是否是您想要的),或者将过滤和打印分开
Stream.evalSeq(fetchS3Buckets)
.parEvalMap(10) { name =>
bucketRegion(name).map(name -> _)
}
.collect { case (name, "my-region") => name }
.parEvalMap(10) { name =>
listObject(name).map(list => println(s"Result: $list"))
}
.compile
.drain
虽然在bare Monix中这些都不是不可能的,但FS2使此类操作更易于编写和维护,因此您应该能够更轻松地实现流程。一旦您有了迭代器[Task[X]],您就可以使用
sequence
将其转换为任务[Iterator[X]]。更好的是,您可能会因为iterator.map(f)
而陷入这种情况,在f
返回任务的地方,您可以执行iterator.traverse(f)
,这将再次为您提供任务[iterator]。然后您可以保留flatMapping
所有内容。PS:我还建议使用一些流媒体解决方案,如果你不想使用fs2,你可以使用monix的obserbavles模型。当你有一个迭代器[Task[X]]时,你可以使用sequence
将它变成一个任务[Iterator[X]]。更好的是,您可能会因为iterator.map(f)
而陷入这种情况,在f
返回任务的地方,您可以执行iterator.traverse(f)
,这将再次为您提供任务[iterator]。然后您可以保留flatMapping
所有内容。PS:我还建议使用一些流媒体解决方案,如果你不想使用fs2,你可以使用monix的obserbavles模制。那要容易得多。我无法告诉你我已经为此挣扎了多久,fs2只是一件轻而易举的事!非常感谢。我很想知道你对Scala的兴趣。你在建造什么样的东西?各种各样的东西。在工作中,我会使用Akka流和活动巴士,但我也会注意FS2,因为我和Akka一样经常使用猫。最近我用FS2做了两个小PoC:和-一个是招聘任务,另一个是围绕游戏引擎的功能包装。我不认为有人会使用它们,但它们可以作为类似的示例/演示。这要容易得多。我无法告诉你我已经为此挣扎了多久,fs2只是一件轻而易举的事!非常感谢。我很想知道你对Scala的兴趣。你在建造什么样的东西?各种各样的东西。在工作中,我会使用Akka流和活动巴士,但我也会注意FS2,因为我和Akka一样经常使用猫。最近我用FS2做了两个小PoC:和-一个是招聘任务,另一个是围绕游戏引擎的功能包装。我不认为有人会使用它们,但它们可以用作类似的示例/演示。