在本地范围内运行scala Futures conncurrently in for comprehension而不使用未来变量。

问题描述 投票:0回答:1

假设我有一个未来的结果,我们把它叫做 garfield

def garfield = Future{
  Thread.sleep(100)
  System.currentTimeMillis()
}

我可以跑 garfield 同时 for comprehension 这样

val f1 = garfield
val f2 = garfield

for {
  r1 <- f1
  r2 <- f2
} yield r1 -> r2

如上所述 这个 的答案。

假设我不想用未来的变量污染局部作用域,如果我以后不需要它们。这是一个有效的替代方法吗?

for {
  f1 <- Future{garfield}
  f2 <- Future{garfield}
  r1 <- f1
  r2 <- f2
} yield r1 -> r2

编辑

看来我原来的方法,使用 Future.apply 包括开销,大部分时间会导致顺序执行,见 例子.

使用替代方法

for {
  f1 <- Future.successful(garfield)
  f2 <- Future.successful(garfield)
  r1 <- f1
  r2 <- f2
} yield r1 -> r2

的表现符合预期。

话又说回来,这种方法有点奇怪,也许更传统的方法是在期货的范围内,在一个 Unit 是首选。

val res = {
  val f1 = garfield
  val f2 = garfield
  for {
    r1 <- f1
    r2 <- f2
  } yield r1 -> r2
}

我很好奇,是否有人能再说明一下零星没有并发执行的原因。

scala future
1个回答
1
投票

For comprehension在本质上是顺序的,所以不,这行不通。

你的代码将依次评估f1和f2。

下面的代码应该是可行的

(更新了一些变化,从 联系 来自@ViktorKlang )

object FutureFor extends App {
  import concurrent.ExecutionContext.Implicits.global

  for {
    _ <- Future.unit
    f1 = Future { "garfield" }
    f2 = Future { "garfield" }
    r1 <- f1
    r2 <- f2
  } yield r1 -> r2

}

你必须从 <- 从 "初始 "的未来消耗,它将决定结果类型的理解。

并发将实现与 = 因为它将创造期货,然后用它们来消费。<-

但这真的很混乱,我建议坚持使用

val f1 = garfield
val f2 = garfield

for {
  r1 <- f1
  r2 <- f2
} yield r1 -> r2

编辑。

你的方法 Future { garfield() } 确实有效,我忽略了一点,它是包装一个未来。

而且它是并发的。请看修改后的代码来证明这一点。

import java.time.Instant
import java.util.concurrent.Executors

import scala.concurrent.{ExecutionContext, Future}
import scala.util.Random

object FutureFor extends App {
  private val random = new Random()
  implicit val ex =
    ExecutionContext.fromExecutor(Executors.newFixedThreadPool(10))

  def garfield() = Future {
    val started = Instant.now()
    Thread.sleep(random.nextInt(1000))
    val stopped = Instant.now()
    s"Started:$started on ${Thread.currentThread().getName}. Stopped $stopped"
  }

  val bar = Future
    .sequence {
      for {
        _ <- 1 to 10
      } yield
        for {
          f1 <- Future { garfield() }
          f2 <- Future { garfield() }
          r1 <- f1
          r2 <- f2
        } yield r1 + "\n" + r2
    }
    .map(_.mkString("\n\n"))
    .foreach(println)

  Thread.sleep(5000)
}

Prints:

Started:2020-04-24T13:23:46.043230Z on pool-1-thread-3. Stopped 2020-04-24T13:23:46.889296Z
Started:2020-04-24T13:23:46.428162Z on pool-1-thread-10. Stopped 2020-04-24T13:23:47.159586Z
....
© www.soinside.com 2019 - 2024. All rights reserved.