【问题标题】:Mixing in asynchronous code within plain synchronous flow in Scala在 Scala 中的普通同步流中混合异步代码
【发布时间】:2015-03-04 19:07:10
【问题描述】:

如果您有一些简单的同步函数调用链,并且您需要在其中添加异步操作而不阻塞,那么您认为最好的 scala 解决方案是什么?

我认为进行期货需要重构现有代码以回调意大利面条,通过以前同步的函数调用链一直束缚期货,或者在每个间隔轮询承诺,不是那么理想,但也许我错过了一些微不足道/合适的选项在这里。

对于(akka)actor 的重构似乎需要大量样板来实现如此简单的工程壮举。

您将如何在现有同步流中插入异步函数,而不会阻塞,也不会涉及大量样板文件?

现在在我的代码中我用Await.result 阻塞,这只是意味着一个线程正在休眠......

【问题讨论】:

  • 你想对异步调用的结果做什么?
  • 感谢您的提问。检查其对下游处理的价值,而不是一劳永逸

标签: scala asynchronous


【解决方案1】:

一个简单的肮脏把戏:

假设你有:

def f1Sync: T1
def f2Sync: T2
...
def fAsynchronous: Future[TAsync]


import scala.concurrent.{ Future, Promise }


object FutureHelper {
  // A value class is much cheaper than an implicit conversion.
  implicit class FutureConverter[T](val t: T) extends AnyVal {
    def future: Future[T] = Promise.successful(t).future
  }

}

那你可以for yield:

import FutureHelper._

def completeChain: Future[Whatever] = {
  for {
    r1 <- f1Sync.future
    r2 <- f2Sync.future
    .. all your syncs
    rn <- fAsynchronous // this should also return a future
    rnn <- f50Sync(rn).future// you can even pass the result of the async to the next function
  } yield rn  
}

将您的同步调用转换为立即解决的期货的样板最少。不要试图用Future.apply[T](t) 或简单的Future(a) 这样做,因为这会将守护线程放到执行器上。如果没有隐式执行器,您将无法转换。

有了 promises,你付出了 3、4 个 promises 的代价,这可以忽略不计,你就得到了你想要的东西。 for yield 充当排序器,它会依次等待每个结果,因此您甚至可以在处理完异步结果后对其进行处理。

它也会“等待”每个同步调用完成,这将在设计上立即发生,除了async 调用将自动采用正常的异步处理。

【讨论】:

    【解决方案2】:

    您还可以使用 async/await 库,但需要注意的是,您最终会得到一个很大的 Future ,您仍然需要处理:

    http://docs.scala-lang.org/sips/pending/async.html

    但是,它产生的代码几乎与同步代码相同;在您之前阻止的地方,您添加:

    await { theAsyncFuture } 
    

    然后继续同步代码。

    【讨论】:

    • 我假设您的意思是实现from here。虽然我现在已经习惯了一直映射future,但在弄清楚它如何分配线程之后,我也可以尝试一下。
    猜你喜欢
    • 2013-10-24
    • 2021-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-05
    • 2018-12-06
    • 1970-01-01
    相关资源
    最近更新 更多