当前位置:网站首页>Scala Future and Promise

Scala Future and Promise

2021-10-22 10:57:42 Bird's nest

Futures and Promises yes Scala The function of language is strengthened : SIP-14. This function is well described in the official documents .
Future Provides a beautiful way to provide the ability to execute code in parallel , Efficient and non blocking .Future Can execute concurrently , Can provide faster , asynchronous , Non blocking concurrent code .
Usually ,future and promise All non blocking execution , You can get the result through the callback function . however , You can also execute serially by blocking Future.
This article is mainly compiled in official documents , And reference to some other online public materials .

Future

One Future Will hold a value , This value will only be available at some point in the future , This value is usually the result of other operations :

  1. If the calculation is not finished , This Future It's not finished yet .
  2. If the calculation is complete ( Get a result or an exception ), This Future It's done .

therefore , Even if Future Already completed , It can also be the following two situations :

  1. Returns a value when the calculation is complete , be future Successfully complete and calculate a result .
  2. An exception occurred when the calculation was completed , be future failed , And will provide an exception object .

Future An important attribute is that it can only be assigned once . Once a Future Object gives a value or exception , It becomes immutable , Its results will never be changed .
and Promise and Future It's a very similar concept , But you can write back results or exceptions .

Simplest creation Future The way of objects is to use future This method is defined as follows :

       
       
       
1
       
       
       
def future[T](body: =>T)(implicit execctx: ExecutionContext): Future[T] = Future[T](body)

The best way to understand it is to look at a code :

       
       
       
1
2
3
4
5
6
       
       
       
import scala.concurrent._
import ExecutionContext.Implicits.global
val session = socialNetwork.createSessionFor( "user", credentials)
val f: Future[List[Friend]] = future {
session.getFriends()
}

session.getFriends() Get the current user's friends from the server , It's a time-consuming operation . This code encapsulates this operation into Future object , It can be executed asynchronously . return Future[List[Friend]] Object as a placeholder . Once the server returns the friends list , Then this Future The object is complete , And the return result can also get .
What if there is an exception when getting the friend list , Such as :

       
       
       
1
2
3
4
       
       
       
val session = null
val f: Future[List[Friend]] = future {
session.getFriends
}

So this Furture failed , Returns an exception .

Get calculation results

As mentioned earlier , According to Future Get the results . Let's show how to calculate the result or exception .

Asynchronous way

Full asynchrony can be achieved through callback . Future Provides onSuccess and onFailure The callback method , Or more abstract onComplete Method .
onComplete The callback function type of the method is :Try[T] => U, It can be applied to Success[T] perhaps Failure[T] On .

Try[T] Similar type Option[T] perhaps Either[T, S], It can be Success[T] perhaps Failure[T], therefore Try[T] Can be seen as Either[Throwable, T].
Illustrate with examples :

       
       
       
1
2
3
4
5
6
7
8
       
       
       
import scala.util.{Success, Failure}
val f: Future[List[String]] = future {
session.getRecentPosts
}
f onComplete {
case Success(posts) => for (post <- posts) println(post)
case Failure(t) => println( "An error has occured: " + t.getMessage)
}

Or it could be :

       
       
       
1
2
3
4
5
6
7
8
9
       
       
       
val f: Future[List[String]] = future {
session.getRecentPosts
}
f onFailure {
case t => println( "An error has occured: " + t.getMessage)
}
f onSuccess {
case posts => for (post <- posts) println(post)
}

What you need to know is that the callback function will not be called until the calculation result is completed . And there is no guarantee that any thread will execute the callback function , But the callback function will eventually be executed .
You can also execute multiple callback functions , Although there is no guarantee of their order of execution :

       
       
       
1
2
3
4
5
6
7
8
9
10
       
       
       
@volatile var totalA = 0
val text = future {
"na" * 16 + "BATMAN!!!"
}
text onSuccess {
case txt => totalA += txt.count(_ == 'a')
}
text onSuccess {
case txt => totalA += txt.count(_ == 'A')
}

After the callback function is executed, it will start from this Future Remove from object , Can be GC.

Synchronization mode

Although we prefer asynchronous callback in most cases Future, However, in some special cases, we still want to execute in the way of synchronous blocking .
Enter the code above :

       
       
       
1
2
3
4
5
       
       
       
import scala.util.{Success, Failure}
val f: Future[List[String]] = future {
session.getRecentPosts
}
Await.result(f, 0 nanos)

adopt Await.result You can get the results of blocking synchronously , Or a timeout , Or throw an exception .
Await.ready Wait for the results to complete , No results returned .

For others, there is nothing like Future Realization Awaitable trait Code for , Blocking can be achieved through the following code :

       
       
       
1
2
3
       
       
       
blocking {
potentiallyBlockingCall()
}

Compound operation

For other frameworks that rely heavily on callbacks , Such as node.js, You often see future In series (chain). One future Depending on another future.
If you follow the previous code , Not very convenient :

       
       
       
1
2
3
4
5
6
7
8
9
10
11
12
13
       
       
       
val rateQuote = future {
connection.getCurrentValue(USD)
}
rateQuote onSuccess { case quote =>
val purchase = future {
if (isProfitable(quote)) connection.buy(amount, quote)
else throw new Exception( "not profitable")
}
purchase onSuccess {
case _ => println( "Purchased " + amount + " USD")
}
}

The above code demonstrates that when it is profitable , Buy dollars .
We have to onSuccess Nested in the second Future. and purchase Of scope Also limited to onSuccess In the method . Imagine if there are four or five nested ,
The code will become terrible .

As a result, these questions ,future Some selectors are provided (combinators), Such as map.

       
       
       
1
2
3
4
5
6
7
8
9
10
       
       
       
val rateQuote = future {
connection.getCurrentValue(USD)
}
val purchase = rateQuote map { quote =>
if (isProfitable(quote)) connection.buy(amount, quote)
else throw new Exception( "not profitable")
}
purchase onSuccess {
case _ => println( "Purchased " + amount + " USD")
}

map first future rateQuote Calculate the successful value , Generate second future. When rateQuote When the failure , There is no value to map,purchase Automatic failure , Exceptions and rateQuote It's the same as the exception .
future also flatMap, filter and foreach Equal selector .
in addition future It also provides failed Mapping function , It returns a value of Throwable Of future, If the previous future success , be failed Back to Future Will throw out NoSuchElementException

Promise

I mainly talked about Future, adopt future Method to create a Future object . We can also go through Promise The way to create future.
Future It's a read-only , Placeholder for values that have not yet been calculated . and Promise Can be regarded as a writable , Single assigned container , Can complete a future. in other words Promise You can call success The method is a Future Successfully completed , perhaps failure Method throws an exception . Or more abstract complete
Such as :

       
       
       
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
       
       
       
import scala.concurrent.{ future, promise }
import scala.concurrent.ExecutionContext.Implicits.global
val p = promise[T]
val f = p.future
val producer = future {
val r = produceSomething()
p success r
continueDoingSomethingUnrelated()
}
val consumer = future {
startDoingSomething()
f onSuccess {
case r => doSomethingWithResult()
}
}

because Promise It's a single assignment , You shouldn't call success perhaps failure two , Otherwise it will throw IllegalStateException.

Reference documents

  1. http://docs.scala-lang.org/sips/completed/futures-promises.html
  2. http://docs.scala-lang.org/sips/completed/futures-promises.html
  3. https://code.csdn.net/DOC_Scala/chinese_scala_offical_document/file/Futures-and-Promises-cn.md
  4. http://programmers.stackexchange.com/questions/207136/what-is-the-difference-between-a-future-and-a-promise

版权声明
本文为[Bird's nest]所创,转载请带上原文链接,感谢
https://chowdera.com/2021/10/20211009000611639O.html

随机推荐