scala Future 如何允许异步执行?
How scala Future allow asynchronous execution?
我是并行执行和 Scala 的新手。
我有几个关于在 scala 中使用 Future 的问题。
我相信 Future 允许异步并行执行。因此,根据我对以下代码的理解,donutStock
方法将在单独的线程上 运行。官方文档也说不会阻塞主线程。所以如果主线程没有阻塞那么新的子线程和主线程应该并行执行。
因此在下面的示例中,我希望一旦调用 donutStock 方法,主线程上的控件就应该继续执行,然后主线程应该在另一个线程上调用第二个 donutStock 方法。
但是,我注意到第二种方法是在第一次调用完成后才调用的。我对非阻塞或异步的理解是否正确?如果我想并行执行这两个方法调用,那么正确的方法是什么。
我读到我们应该在服务器主线程中执行异步操作。在这种情况下异步操作的优势是什么
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
def donutStock(donut: String): Future[Int] = Future {
(1 until 100).foreach { value ⇒
println(s"checking donut stock $donut")
}
10
}
donutStock("My Donut").onComplete{
case Success(value) ⇒ println("Call 1 Completed")
case Failure(exception) ⇒ println("Call 1 Failed")
}
donutStock("Your Donut").onComplete{
case Success(value) ⇒ println("Call 2 Completed")
case Failure(exception) ⇒ println("Call 2 Failed")
}
Futures are the standard mechanism for writing multi threaded code in Scala. Whenever we create a new Future operation, Scala spawns a new thread to run that Future’s code, and after completion it executes any provided callbacks.
In order to use Futures, Scala requires us to provide an implicit execution context, which controls the thread pool in which Futures execute. We can create our own execution contexts, or use the default one which usually suffices. The default execution context is backed by Fork Join Thread Pool. From code its obvious that the example uses implicit one.
def donutStock(donut: String): Future[Int] = Future {
(1 until 100).foreach { value ⇒
println(s"checking donut stock $donut")
}
10
}
当函数 donutStock(<string>)
with return 类型为 Future[Int]
.
时,上面包含的代码将在其自己的线程中执行
Scala 允许我们定义回调函数,它在 Future 成功或失败时执行。与此同时,创建 Future 的线程被解除阻塞,可以继续执行如下,
donutStock("My Donut").onComplete{
case Success(value) ⇒ println("Call 1 Completed")
case Failure(exception) ⇒ println("Call 1 Failed")
}
donutStock("Your Donut").onComplete{
case Success(value) ⇒ println("Call 2 Completed")
case Failure(exception) ⇒ println("Call 2 Failed")
}
在 Future donutStock() 成功完成后,onComplete 回调会收到一个 Success 对象,其中包含 10
的结果。
创建未来时,它通常会立即使用一个线程开始。如果在您当前的执行上下文中没有可用的线程,那么它可能不会立即启动您的未来,而是等到线程被释放。
如果您的执行上下文中只有一个线程可用,那么下一个 future 的执行将不得不等待前一个 future 完成。
通常,执行上下文的线程数多于可用线程数(例如,在 scala 的全局执行上下文中,线程数默认为可用线程数)。
在你的情况下,问题可能是,你的第一个未来可能完成得太快,以至于它在第二个开始之前就完成了。
您可以通过在打印值后引入小的延迟来缓解它,例如在 println(s"checking donut stock $donut")
之后添加 Thread.sleep(10)
。
此更改后,您的未来执行速度会变慢
这可能会导致另一个问题,因为 futures 在守护线程中启动,可能会发生,主线程将在 futures 执行结束之前终止。在这种情况下,它们将在调用 onComplete
回调之前终止。
您可以避免这种情况,您可以使用 Await
等待两个期货,例如:
import scala.concurrent._
import scala.concurrent.duration._
val f1 = donutStock("My Donut").onComplete{
case Success(value) ⇒ println("Call 1 Completed")
case Failure(exception) ⇒ println("Call 1 Failed")
}
val f2 = donutStock("Your Donut").onComplete{
case Success(value) ⇒ println("Call 2 Completed")
case Failure(exception) ⇒ println("Call 2 Failed")
}
val result1 = Await.result(f1, 1 second)
val result2 = Await.result(f2, 1 second)
如果我们可以等待未来,onComplete
回调的用例是什么?例如,当我们定义一个返回 Future 的函数并且我们不想使用 Await
阻止它但我们仍然希望在 future 完成时执行一些操作时,它可能会有所帮助。
例如,您可以如下修改 donutStock
:
def donutStock(donut: String, idx: Int): Future[Int] = {
val f = Future {
(1 until 100).foreach { value ⇒
println(s"checking donut stock $donut")
}
10
}
//we don't block future, but onComplete callback will be still executed when future ends
f.onComplete{
case Success(value) ⇒ println(s"Call $idx Completed")
case Failure(exception) ⇒ println(s"Call $idx Failed")
}
f
}
我是并行执行和 Scala 的新手。 我有几个关于在 scala 中使用 Future 的问题。
我相信 Future 允许异步并行执行。因此,根据我对以下代码的理解,donutStock
方法将在单独的线程上 运行。官方文档也说不会阻塞主线程。所以如果主线程没有阻塞那么新的子线程和主线程应该并行执行。
因此在下面的示例中,我希望一旦调用 donutStock 方法,主线程上的控件就应该继续执行,然后主线程应该在另一个线程上调用第二个 donutStock 方法。
但是,我注意到第二种方法是在第一次调用完成后才调用的。我对非阻塞或异步的理解是否正确?如果我想并行执行这两个方法调用,那么正确的方法是什么。
我读到我们应该在服务器主线程中执行异步操作。在这种情况下异步操作的优势是什么
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
def donutStock(donut: String): Future[Int] = Future {
(1 until 100).foreach { value ⇒
println(s"checking donut stock $donut")
}
10
}
donutStock("My Donut").onComplete{
case Success(value) ⇒ println("Call 1 Completed")
case Failure(exception) ⇒ println("Call 1 Failed")
}
donutStock("Your Donut").onComplete{
case Success(value) ⇒ println("Call 2 Completed")
case Failure(exception) ⇒ println("Call 2 Failed")
}
Futures are the standard mechanism for writing multi threaded code in Scala. Whenever we create a new Future operation, Scala spawns a new thread to run that Future’s code, and after completion it executes any provided callbacks.
In order to use Futures, Scala requires us to provide an implicit execution context, which controls the thread pool in which Futures execute. We can create our own execution contexts, or use the default one which usually suffices. The default execution context is backed by Fork Join Thread Pool. From code its obvious that the example uses implicit one.
def donutStock(donut: String): Future[Int] = Future {
(1 until 100).foreach { value ⇒
println(s"checking donut stock $donut")
}
10
}
当函数 donutStock(<string>)
with return 类型为 Future[Int]
.
Scala 允许我们定义回调函数,它在 Future 成功或失败时执行。与此同时,创建 Future 的线程被解除阻塞,可以继续执行如下,
donutStock("My Donut").onComplete{
case Success(value) ⇒ println("Call 1 Completed")
case Failure(exception) ⇒ println("Call 1 Failed")
}
donutStock("Your Donut").onComplete{
case Success(value) ⇒ println("Call 2 Completed")
case Failure(exception) ⇒ println("Call 2 Failed")
}
在 Future donutStock() 成功完成后,onComplete 回调会收到一个 Success 对象,其中包含 10
的结果。
创建未来时,它通常会立即使用一个线程开始。如果在您当前的执行上下文中没有可用的线程,那么它可能不会立即启动您的未来,而是等到线程被释放。
如果您的执行上下文中只有一个线程可用,那么下一个 future 的执行将不得不等待前一个 future 完成。
通常,执行上下文的线程数多于可用线程数(例如,在 scala 的全局执行上下文中,线程数默认为可用线程数)。
在你的情况下,问题可能是,你的第一个未来可能完成得太快,以至于它在第二个开始之前就完成了。
您可以通过在打印值后引入小的延迟来缓解它,例如在 println(s"checking donut stock $donut")
之后添加 Thread.sleep(10)
。
此更改后,您的未来执行速度会变慢
这可能会导致另一个问题,因为 futures 在守护线程中启动,可能会发生,主线程将在 futures 执行结束之前终止。在这种情况下,它们将在调用 onComplete
回调之前终止。
您可以避免这种情况,您可以使用 Await
等待两个期货,例如:
import scala.concurrent._
import scala.concurrent.duration._
val f1 = donutStock("My Donut").onComplete{
case Success(value) ⇒ println("Call 1 Completed")
case Failure(exception) ⇒ println("Call 1 Failed")
}
val f2 = donutStock("Your Donut").onComplete{
case Success(value) ⇒ println("Call 2 Completed")
case Failure(exception) ⇒ println("Call 2 Failed")
}
val result1 = Await.result(f1, 1 second)
val result2 = Await.result(f2, 1 second)
如果我们可以等待未来,onComplete
回调的用例是什么?例如,当我们定义一个返回 Future 的函数并且我们不想使用 Await
阻止它但我们仍然希望在 future 完成时执行一些操作时,它可能会有所帮助。
例如,您可以如下修改 donutStock
:
def donutStock(donut: String, idx: Int): Future[Int] = {
val f = Future {
(1 until 100).foreach { value ⇒
println(s"checking donut stock $donut")
}
10
}
//we don't block future, but onComplete callback will be still executed when future ends
f.onComplete{
case Success(value) ⇒ println(s"Call $idx Completed")
case Failure(exception) ⇒ println(s"Call $idx Failed")
}
f
}