在Scala的未来行为不一致时遇到麻烦

时间:2013-12-01 05:43:03

标签: scala functional-programming promise future

我面临着Scala未来行为不一致的问题。以下是我的代码

package TryFuture

import scala.concurrent.Future
import scala.concurrent.future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.util.Random

class FutureCappuccino {
  // Some type aliases, just for getting more meaningful method signatures:
  type CoffeeBeans = String
  type GroundCoffee = String
  case class Water(temperature: Int)
  type Milk = String
  type FrothedMilk = String
  type Espresso = String
  type Cappuccino = String

  // some exceptions for things that might go wrong in the individual steps
  // (we'll need some of them later, use the others when experimenting
  // with the code):
  case class GrindingException(msg: String) extends Exception(msg)
  case class FrothingException(msg: String) extends Exception(msg)
  case class WaterBoilingException(msg: String) extends Exception(msg)
  case class BrewingException(msg: String) extends Exception(msg)

  def grind(beans: CoffeeBeans): Future[GroundCoffee] = future {
    println("Start grinding with thread: " + Thread.currentThread().getId())
    //Thread.sleep(10)
    if (beans == "baked beans") throw GrindingException("are you joking?")
    println("Finished grinding..")
    s"ground coffee of $beans"
  }

  def heatWater(water: Water): Future[Water] = future {
    println("Heating the water with thread: " + Thread.currentThread().getId())
    //Thread.sleep(10)
    println("It's hot!!")
    water.copy(temperature = 85)
  }

  def frothMilk(milk: Milk): Future[FrothedMilk] = future {
    println("milk frothing system engaged! with thread: " + Thread.currentThread().getId())
    //Thread.sleep(Random.nextInt(10))
    println("shutting down milk frothing system")
    s"frothed $milk"
  }

  def brew(coffee: GroundCoffee, heatedWater: Water): Future[Espresso] = future {
    println("happy brewing :) with thread: " + Thread.currentThread().getId())
    //Thread.sleep(Random.nextInt(10))
    println("it's brewed!")
    s"espresso"
  }

  def combine(espresso: Espresso, frothedMilk: FrothedMilk): Future[String] = future {
    println("Combine starting with thread: " + Thread.currentThread().getId())
    "Your Cappuccino is ready"
  }

  // going through these steps sequentially:
  def prepareCappuccino() = {
    val brewed = for {
      coffee <- grind("not baked beans")
      water <- heatWater(Water(25))
      brewed <- brew(coffee, water)
    } yield brewed

    brewed
  }

}

现在我所期待的是水将等待研磨完成然后酿造将等待研磨和热水完成。但是当我在MacBook上运行这个程序时,我只得到了下面的o / p 用螺纹开始磨削:8然后执行完成。它不是在等待剩下的东西。无法找到我在这里缺少的东西以及它为什么不等待?有什么帮助吗?

2 个答案:

答案 0 :(得分:1)

def grind(beans: CoffeeBeans): Future[GroundCoffee] = future {
    println("Start grinding with thread: " + Thread.currentThread().getId())

    if (beans == "baked beans") throw GrindingException("are you joking?")

    ...
}

def prepareCappuccino() = {
  val brewed = for {
    coffee <- grind("baked beans")
    water <- heatWater(Water(25))
    brewed <- brew(coffee, water)
  } yield brewed

  brewed
}

grind方法抛出异常,导致for表达式导致失败 将来

grind传递“not baked beans”时,它会按预期工作。

您的主要线程太快退出。

使用Thread.sleep或Await.result

答案 1 :(得分:0)

最后通过以下更改明确了概念:

package TryFuture

import scala.concurrent.Future
import scala.concurrent.future
import scala.util.{Success,Failure}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.util.Random

class FutureCappuccino {
  // Some type aliases, just for getting more meaningful method signatures:
  type CoffeeBeans = String
  type GroundCoffee = String
  case class Water(temperature: Int)
  type Milk = String
  type FrothedMilk = String
  type Espresso = String
  type Cappuccino = String

  // some exceptions for things that might go wrong in the individual steps
  // (we'll need some of them later, use the others when experimenting
  // with the code):
  case class GrindingException(msg: String) extends Exception(msg)
  case class FrothingException(msg: String) extends Exception(msg)
  case class WaterBoilingException(msg: String) extends Exception(msg)
  case class BrewingException(msg: String) extends Exception(msg)

  def grind(beans: CoffeeBeans): Future[GroundCoffee] = {
    println("Start grinding with thread: " + Thread.currentThread().getId())
    Thread.sleep(200)
    if (beans == "baked beans") throw GrindingException("are you joking?")
    future {
      Thread.sleep(200)
      s"ground coffee of $beans"
    }
  }

  def heatWater(water: Water): Future[Water] = {
    println("Heating the water with thread: " + Thread.currentThread().getId())
    Thread.sleep(200)
    future {
      water.copy(temperature = 85)
    }
  }

  def frothMilk(milk: Milk): Future[FrothedMilk] = {
    println("milk frothing system engaged! with thread: " + Thread.currentThread().getId())
    Thread.sleep(200)
    future {
      s"frothed $milk"
    }
  }

  def brew(coffee: GroundCoffee, heatedWater: Water): Future[Espresso] = {
    println("happy brewing :) with thread: " + Thread.currentThread().getId())
    Thread.sleep(200)
    future {
      s"espresso"
    }
  }

  def combine(espresso: Espresso, frothedMilk: FrothedMilk): Future[String] =  {
    println("Combine starting with thread: " + Thread.currentThread().getId())
    Thread.sleep(200)
    future {
      Thread.sleep(20)
      "Your Cappuccino is ready"
    }
  }

  // going through these steps sequentially:
  def prepareCappuccino() = {
    val coffees = grind("not baked beans")
    val waters = heatWater(Water(25))
    val milks = frothMilk("milk")

    val combined = for {
      coffee <- coffees
      water <- waters
      brewed <- brew(coffee, water)
      milk <- milks
      combined <- combine(brewed, milk)
    } yield combined

    combined onComplete {
      case Success(t)   => println("combined is done")
      case Failure(t)   => t
    }

    coffees onComplete {
      case Success(t)   => println("Coffee is done")
      case Failure(t)   => t
    }

    combined

  }

}

最后====&gt;

val myFutureCappuccino = new FutureCappuccino()
  val myCoffee = myFutureCappuccino.prepareCappuccino
  Thread.sleep(2000)
  myCoffee onComplete{
    case Success(t) =>  println(t)
    case Failure(p) =>  println(p.getMessage())
  }

现在对输出很满意:

Start grinding with thread: 1
Heating the water with thread: 1
milk frothing system engaged! with thread: 1
happy brewing :) with thread: 8
Coffee is done
Combine starting with thread: 8
combined is done
Your Cappuccino is ready

在这里分享答案,希望它可以帮助某人。感谢。