首页 文章

Scala Future中如何发生这种僵局?

提问于
浏览
1

此片段摘自Monix document . 这是一个如何在Scala中输入死锁的示例 .

import java.util.concurrent.Executors
import scala.concurrent._
implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(1))

def addOne(x: Int) = Future(x + 1)

def multiply(x: Int, y: Int) = Future {
  val a = addOne(x)
  val b = addOne(y)
  val result = for (r1 <- a; r2 <- b) yield r1 * r2

  // This can dead-lock due to the limited size of our thread-pool!
  Await.result(result, Duration.Inf)
}

我理解代码的作用,但不了解它是如何执行的 .

为什么导致死锁的是 Await.result(result, Duration.Inf) ? (是的,我测试过了)

是不是最左边的 Future 乘法函数占用了所有的线程池(单个)并因此死锁(因为addOne future在等待线程时永远被阻塞)?

3 回答

  • 2

    并不是乘法函数中最外层的Future占用所有线程池(单个)并因此死锁(因为addOne future在等待线程时永远被阻塞)?

    是的,有点 .

    当您调用 val a = addOne(x) 时,您将创建一个开始等待线程的新Future . 但是,正如您所指出的,最外层的Future目前正在使用唯一的线程 . 没有等待就不会有问题,因为Futures能够处理这种情况 . 但是,这一行:

    Await.result(result, Duration.Inf)
    

    导致外部未来等待 result 未来,因为 ab 期货无法再次运行,因为外部的未来将继续运行 . )

    这是一个更简单的例子,在没有创建如此多的期货的情况下也会陷入僵局:

    def addTwo(x: Int) = Future {
      Await.result(addOne(x + 1), Duration.Inf)
    }
    
  • 0

    首先我要说 this code can simulate deadlock, it’s not guaranteed that it will always be in the deadlock. 以上代码中发生了什么 . 我们在线程池中只有一个线程 . 一旦我们调用了多个函数,因为它是未来所以它应该在一个单独的线程上运行,说我们将线程池中的单个线程分配给这个函数 . 现在函数addOne也是未来所以它将再次开始在同一个线程上运行,但是不会等待a = addOne来完成并移动到下一行b = addOne因此执行a = addOne的同一个线程现在执行b = addOne并且所有的值永远不会被计算,并且未来不会完整而且永远不会完整,因为我们只有一个线程,与b = addOne行相同的情况它控制不会等待完成未来和移动到for循环for也是Scala中的异步,因此它将再次不被评估并移动到最后一行等待它将等待无限量的时间来完成前一个期货 .

    Necessary and sufficient condition to get into the dead lock.

    • 互斥条件

    • 保持和等待条件

    • 无抢先条件

    • 循环等待条件

    在这里我们可以看到我们只有一个线程,因此要执行的进程不是互斥的 .

    一旦线程正在执行特定的块,因此它是一个未来而不是等待完成它,它继续执行下一个块,因此它到达await语句并且线程保持在那里,而所有其他未来的未完成的是等待线程完成未来 .

    一旦线程被分配给await就不能抢占,这就是我们无法执行未完成的剩余未来的原因 .

    因为等待等待非完整的未来完成而其他期货正在等待等待呼叫完成,因此存在循环等待 .

    简单地说,我们可以说控制将直接到达await语句并开始等待非完整的期货得到完成,这无论如何都不会发生 . 因为我们的线程池中只有一个线程 .

  • 1
    Await.result(result, Duration.Inf)
    

    当您使用 await 时,您正在等待将来完成 . 你给了无限的时间 . 因此,无论如何Future永远无法完成,主线程将无限期等待 .

相关问题