Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 使用流对多个函数调用进行建模(以安全、FP的方式)_Scala_Scala Cats_Fs2_Http4s_Monix - Fatal编程技术网

Scala 使用流对多个函数调用进行建模(以安全、FP的方式)

Scala 使用流对多个函数调用进行建模(以安全、FP的方式),scala,scala-cats,fs2,http4s,monix,Scala,Scala Cats,Fs2,Http4s,Monix,给定一个函数a=>IO[B](又称Kleisli[IO,a,B]),它意味着要被多次调用,并且有副作用,比如更新数据库,如何将它的多次调用委托到一个流中(我猜Pipe[IO,a,B])(fs2,monix observatable/iterant)?这样做的原因是能够在一个时间窗口内累积状态、批处理调用等 更具体地说,http4s服务器需要一个请求=>IO[Response],因此我正在研究如何对流进行操作(为了实现上述好处),但最终为http4s提供了这样一个功能 我怀疑它在幕后需要一些相关I

给定一个函数
a=>IO[B]
(又称
Kleisli[IO,a,B]
),它意味着要被多次调用,并且有副作用,比如更新数据库,如何将它的多次调用委托到一个流中(我猜
Pipe[IO,a,B]
)(fs2,monix observatable/iterant)?这样做的原因是能够在一个时间窗口内累积状态、批处理调用等

更具体地说,http4s服务器需要一个
请求=>IO[Response]
,因此我正在研究如何对流进行操作(为了实现上述好处),但最终为http4s提供了这样一个功能

我怀疑它在幕后需要一些相关ID,我对此很满意,我更感兴趣的是如何从FP的角度安全、正确地完成它

最终,我期望的签名可能是:

管道[IO,A,B]=>(A=>IO[B])
,这样对Kleisli的调用通过管道进行


事后想一想,是否有可能产生反压力

一个想法是使用MPSC(多发行商单消费者)对其进行建模。我将举一个关于Monix的例子,因为我对它比较熟悉,但是即使使用FS2,这个想法也不会改变

object MPSC extends App {

  sealed trait Event
  object Event {
    // You'll need a promise in order to send the response back to user
    case class SaveItem(num: Int, promise: Deferred[Task, Int]) extends Event
  }

  // For backpressure, take a look at `PublishSubject`.
  val cs = ConcurrentSubject[Event](MulticastStrategy.Publish)

  def pushEvent(num: Int) = {
    for {
      promise <- Deferred[Task, Int]
      _ <- Task.delay(cs.onNext(SaveItem(num, promise)))
    } yield promise
  }

  // You get a list of events now since it is buffered
  // Monix has a lot of buffer strategies, check the docs for more details
  def processEvents(items: Seq[Event]): Task[Unit] = {
    Task.delay(println(s"Items: $items")) >>
      Task.traverse(items) {
        case SaveItem(_, promise) => promise.complete(Random.nextInt(100))
      }.void
  }

  val app = for {
    // Start the stream in the background
    _ <- cs
      .bufferTimed(3.seconds) // Buffer all events within 3 seconds
      .filter(_.nonEmpty)
      .mapEval(processEvents)
      .completedL
      .startAndForget

    _ <- Task.sleep(1.second)
    p1 <- pushEvent(10)
    p2 <- pushEvent(20)
    p3 <- pushEvent(30)

    // Wait for the promise to complete, you'll do this for each request
    x <- p1.get
    y <- p2.get
    z <- p3.get

    _ <- Task.delay(println(s"Completed promise: [$x, $y, $z]"))
  } yield ()

  app.runSyncUnsafe()
}
对象MPSC扩展应用程序{
封闭特征事件
对象事件{
//您需要承诺才能将响应发送回用户
案例类SaveItem(num:Int,promise:Deferred[Task,Int])扩展事件
}
//有关背压,请查看“PublishSubject”。
val cs=ConcurrentSubject[事件](MulticastStrategy.Publish)
def pushEvent(数值:整数)={
为了{
允诺
任务.遍历(项){
case SaveItem(u,promise)=>promise.complete(Random.nextInt(100))
}.无效
}
val app=用于{
//在后台启动流

_如果我理解正确,您希望在HTTP调用之间累积状态?因为我不理解“一起批处理调用”的含义当您落后于http4s时?是的,累积状态是一般的想法。例如,您可能希望在2秒内批处理多个
GET
s,使用
in
子句将同一个表查询成一个查询,以增加吞吐量(以延迟为代价)为什么不像transformers那样的
StateT
?它们确实提供了有状态计算的能力。不,我想到了
StateT
,但既不符合具有透明状态的Kleisli的要求,也不符合对窗口操作的后续调用的访问。我发现,为了实现tch请求HTTP服务,并因此延迟每个请求。也许我不在正确的上下文中,但您为什么要这样做?