数学基础
- 线性代数
- 概率论与随机过程
- 数值计算
- 蒙特卡洛方法与 MCMC 采样
- 机器学习方法概论
统计学习
深度学习
- 深度学习简介
- 深度前馈网络
- 反向传播算法
- 正则化
- 深度学习中的最优化问题
- 卷积神经网络
- CNN:图像分类
- 循环神经网络 RNN
- Transformer
- 一、Transformer [2017]
- 二、Universal Transformer [2018]
- 三、Transformer-XL [2019]
- 四、GPT1 [2018]
- 五、GPT2 [2019]
- 六、GPT3 [2020]
- 七、OPT [2022]
- 八、BERT [2018]
- 九、XLNet [2019]
- 十、RoBERTa [2019]
- 十一、ERNIE 1.0 [2019]
- 十二、ERNIE 2.0 [2019]
- 十三、ERNIE 3.0 [2021]
- 十四、ERNIE-Huawei [2019]
- 十五、MT-DNN [2019]
- 十六、BART [2019]
- 十七、mBART [2020]
- 十八、SpanBERT [2019]
- 十九、ALBERT [2019]
- 二十、UniLM [2019]
- 二十一、MASS [2019]
- 二十二、MacBERT [2019]
- 二十三、Fine-Tuning Language Models from Human Preferences [2019]
- 二十四 Learning to summarize from human feedback [2020]
- 二十五、InstructGPT [2022]
- 二十六、T5 [2020]
- 二十七、mT5 [2020]
- 二十八、ExT5 [2021]
- 二十九、Muppet [2021]
- 三十、Self-Attention with Relative Position Representations [2018]
- 三十一、USE [2018]
- 三十二、Sentence-BERT [2019]
- 三十三、SimCSE [2021]
- 三十四、BERT-Flow [2020]
- 三十五、BERT-Whitening [2021]
- 三十六、Comparing the Geometry of BERT, ELMo, and GPT-2 Embeddings [2019]
- 三十七、CERT [2020]
- 三十八、DeCLUTR [2020]
- 三十九、CLEAR [2020]
- 四十、ConSERT [2021]
- 四十一、Sentence-T5 [2021]
- 四十二、ULMFiT [2018]
- 四十三、Scaling Laws for Neural Language Models [2020]
- 四十四、Chinchilla [2022]
- 四十七、GLM-130B [2022]
- 四十八、GPT-NeoX-20B [2022]
- 四十九、Bloom [2022]
- 五十、PaLM [2022] (粗读)
- 五十一、PaLM2 [2023](粗读)
- 五十二、Self-Instruct [2022]
- 句子向量
- 词向量
- 传统CTR 预估模型
- CTR 预估模型
- 一、DSSM [2013]
- 二、FNN [2016]
- 三、PNN [2016]
- 四、DeepCrossing [2016]
- 五、Wide 和 Deep [2016]
- 六、DCN [2017]
- 七、DeepFM [2017]
- 八、NFM [2017]
- 九、AFM [2017]
- 十、xDeepFM [2018]
- 十一、ESMM [2018]
- 十二、DIN [2017]
- 十三、DIEN [2019]
- 十四、DSIN [2019]
- 十五、DICM [2017]
- 十六、DeepMCP [2019]
- 十七、MIMN [2019]
- 十八、DMR [2020]
- 十九、MiNet [2020]
- 二十、DSTN [2019]
- 二十一、BST [2019]
- 二十二、SIM [2020]
- 二十三、ESM2 [2019]
- 二十四、MV-DNN [2015]
- 二十五、CAN [2020]
- 二十六、AutoInt [2018]
- 二十七、Fi-GNN [2019]
- 二十八、FwFM [2018]
- 二十九、FM2 [2021]
- 三十、FiBiNET [2019]
- 三十一、AutoFIS [2020]
- 三十三、AFN [2020]
- 三十四、FGCNN [2019]
- 三十五、AutoCross [2019]
- 三十六、InterHAt [2020]
- 三十七、xDeepInt [2023]
- 三十九、AutoDis [2021]
- 四十、MDE [2020]
- 四十一、NIS [2020]
- 四十二、AutoEmb [2020]
- 四十三、AutoDim [2021]
- 四十四、PEP [2021]
- 四十五、DeepLight [2021]
- 图的表达
- 一、DeepWalk [2014]
- 二、LINE [2015]
- 三、GraRep [2015]
- 四、TADW [2015]
- 五、DNGR [2016]
- 六、Node2Vec [2016]
- 七、WALKLETS [2016]
- 八、SDNE [2016]
- 九、CANE [2017]
- 十、EOE [2017]
- 十一、metapath2vec [2017]
- 十二、GraphGAN [2018]
- 十三、struc2vec [2017]
- 十四、GraphWave [2018]
- 十五、NetMF [2017]
- 十六、NetSMF [2019]
- 十七、PTE [2015]
- 十八、HNE [2015]
- 十九、AANE [2017]
- 二十、LANE [2017]
- 二十一、MVE [2017]
- 二十二、PMNE [2017]
- 二十三、ANRL [2018]
- 二十四、DANE [2018]
- 二十五、HERec [2018]
- 二十六、GATNE [2019]
- 二十七、MNE [2018]
- 二十八、MVN2VEC [2018]
- 二十九、SNE [2018]
- 三十、ProNE [2019]
- Graph Embedding 综述
- 图神经网络
- 一、GNN [2009]
- 二、Spectral Networks 和 Deep Locally Connected Networks [2013]
- 三、Fast Localized Spectral Filtering On Graph [2016]
- 四、GCN [2016]
- 五、神经图指纹 [2015]
- 六、GGS-NN [2016]
- 七、PATCHY-SAN [2016]
- 八、GraphSAGE [2017]
- 九、GAT [2017]
- 十、R-GCN [2017]
- 十一、 AGCN [2018]
- 十二、FastGCN [2018]
- 十三、PinSage [2018]
- 十四、GCMC [2017]
- 十五、JK-Net [2018]
- 十六、PPNP [2018]
- 十七、VRGCN [2017]
- 十八、ClusterGCN [2019]
- 十九、LDS-GNN [2019]
- 二十、DIAL-GNN [2019]
- 二十一、HAN [2019]
- 二十二、HetGNN [2019]
- 二十三、HGT [2020]
- 二十四、GPT-GNN [2020]
- 二十五、Geom-GCN [2020]
- 二十六、Graph Network [2018]
- 二十七、GIN [2019]
- 二十八、MPNN [2017]
- 二十九、UniMP [2020]
- 三十、Correct and Smooth [2020]
- 三十一、LGCN [2018]
- 三十二、DGCNN [2018]
- 三十三、AS-GCN
- 三十四、DGI [2018]
- 三十五、DIFFPOLL [2018]
- 三十六、DCNN [2016]
- 三十七、IN [2016]
- 图神经网络 2
- 图神经网络 3
- 推荐算法(传统方法)
- 一、Tapestry [1992]
- 二、GroupLens [1994]
- 三、ItemBased CF [2001]
- 四、Amazon I-2-I CF [2003]
- 五、Slope One Rating-Based CF [2005]
- 六、Bipartite Network Projection [2007]
- 七、Implicit Feedback CF [2008]
- 八、PMF [2008]
- 九、SVD++ [2008]
- 十、MMMF 扩展 [2008]
- 十一、OCCF [2008]
- 十二、BPR [2009]
- 十三、MF for RS [2009]
- 十四、 Netflix BellKor Solution [2009]
- 推荐算法(神经网络方法 1)
- 一、MIND [2019](用于召回)
- 二、DNN For YouTube [2016]
- 三、Recommending What Video to Watch Next [2019]
- 四、ESAM [2020]
- 五、Facebook Embedding Based Retrieval [2020](用于检索)
- 六、Airbnb Search Ranking [2018]
- 七、MOBIUS [2019](用于召回)
- 八、TDM [2018](用于检索)
- 九、DR [2020](用于检索)
- 十、JTM [2019](用于检索)
- 十一、Pinterest Recommender System [2017]
- 十二、DLRM [2019]
- 十三、Applying Deep Learning To Airbnb Search [2018]
- 十四、Improving Deep Learning For Airbnb Search [2020]
- 十五、HOP-Rec [2018]
- 十六、NCF [2017]
- 十七、NGCF [2019]
- 十八、LightGCN [2020]
- 十九、Sampling-Bias-Corrected Neural Modeling [2019](检索)
- 二十、EGES [2018](Matching 阶段)
- 二十一、SDM [2019](Matching 阶段)
- 二十二、COLD [2020 ] (Pre-Ranking 模型)
- 二十三、ComiRec [2020](https://www.wenjiangs.com/doc/0b4e1736-ac78)
- 二十四、EdgeRec [2020]
- 二十五、DPSR [2020](检索)
- 二十六、PDN [2021](mathcing)
- 二十七、时空周期兴趣学习网络ST-PIL [2021]
- 推荐算法之序列推荐
- 一、FPMC [2010]
- 二、GRU4Rec [2015]
- 三、HRM [2015]
- 四、DREAM [2016]
- 五、Improved GRU4Rec [2016]
- 六、NARM [2017]
- 七、HRNN [2017]
- 八、RRN [2017]
- 九、Caser [2018]
- 十、p-RNN [2016]
- 十一、GRU4Rec Top-k Gains [2018]
- 十二、SASRec [2018]
- 十三、RUM [2018]
- 十四、SHAN [2018]
- 十五、Phased LSTM [2016]
- 十六、Time-LSTM [2017]
- 十七、STAMP [2018]
- 十八、Latent Cross [2018]
- 十九、CSRM [2019]
- 二十、SR-GNN [2019]
- 二十一、GC-SAN [2019]
- 二十二、BERT4Rec [2019]
- 二十三、MCPRN [2019]
- 二十四、RepeatNet [2019]
- 二十五、LINet(2019)
- 二十六、NextItNet [2019]
- 二十七、GCE-GNN [2020]
- 二十八、LESSR [2020]
- 二十九、HyperRec [2020]
- 三十、DHCN [2021]
- 三十一、TiSASRec [2020]
- 推荐算法(综述)
- 多任务学习
- 系统架构
- 实践方法论
- 深度强化学习 1
- 自动代码生成
工具
- CRF
- lightgbm
- xgboost
- scikit-learn
- spark
- numpy
- matplotlib
- pandas
- huggingface_transformer
- 一、Tokenizer
- 二、Datasets
- 三、Model
- 四、Trainer
- 五、Evaluator
- 六、Pipeline
- 七、Accelerate
- 八、Autoclass
- 九、应用
- 十、Gradio
Scala
- 环境搭建
- 基础知识
- 函数
- 类
- 样例类和模式匹配
- 测试和注解
- 集合 collection(一)
- 集合collection(二)
- 集成 Java
- 并发
二、使用 Future
2.1 基础变换
在
Scala
中,你可以对Future
的结果指定变换,然后得到一个新的Future
,从而表示这两个异步计算的组合:原始的异步计算和异步变换。最基础的变换是
map
,可以直接将下一个计算map
到当前的Future
,而不是阻塞等待结果。map
之后得到一个新的Future
,表示原始的异步计算经过传给map
的函数异步变换之后的结果。xxxxxxxxxx
val fut = Future{ Thread.sleep(10000); 21 + 21} // 异步计算 val fut2 = fut.map( x => x +1) // 异步变换当异步计算和异步变换完成之后,
fut2.value
返回Some(Success(43))
。注意:这里创建
fut, fut2
的线程、fut
的异步计算线程、fut2
的异步变换线程可能分别在三个不同的线程中执行。还可以使用
for
表达式来对Future
进行变换。考虑两个Future
:xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21 + 21} val fut2 = Future{ Thread.sleep(10000); 23 + 23}可以通过
for
表达式来构造一个新的Future
:xxxxxxxxxx
for { x <- fut1 y <- fut2 } yield x + y一旦这三个
Future
完成,你将会得到最终结果为Some(Success(88))
。注意:因为
for
表达式会串行化它们的变换,因此如果你没有在for
之前创建好Future
,则它们并不会并行执行。如:xxxxxxxxxx
//*************************** fut1, fut2 并行执行 *******************// val fut1 = Future{ Thread.sleep(10000); 21 + 21} val fut2 = Future{ Thread.sleep(10000); 23 + 23} val result = for { x <- fut1 y <- fut2 } yield x + y //*************************** fut1, fut2 串行执行 *******************// val result2 = for { x <- Future{ Thread.sleep(10000); 21 + 21} y <- Future{ Thread.sleep(10000); 23 + 23} } yield x + y事实上这里的
for
表达式会被重写为fut1.flatMap(x => fut2.map(y => x + y))
。可以通过
Future
伴生对象的几个方法来创建Future
:Future
伴生对象的apply
方法,如Future{ Thread.sleep(10000); 21 + 21}
。Future
伴生对象的Future.failed, Future.successful, Future.fromTry
等工厂方法。这些工厂方法并不需要ExecutionContext
。successful
工厂方法将创建一个已经成功完成的Future
:xxxxxxxxxx
Future.successful{ 21 + 21}failed
工厂方法将创建一个已经失败的Future
:xxxxxxxxxx
Future.failed( new Exception("xxx Exception"))fromTry
工厂方法将从给定的Try
创建一个已经完成的Future
:xxxxxxxxxx
import scala.util.{Success, Failure} Future.fromTry(Success {21 + 21}) Future.fromTry(Failure(new Exception("xxx Exception")))
创建
Future
最一般化的方法是使用Promise
。给定一个Promise
,可以得到由这个Promise
控制的Future
。当你完成Promise
时,对应的Future
也会完成。xxxxxxxxxx
val pro = Promise[Int] val fut = pro.future可以用名为
success, failure, complete
的方法来完成Promise
。这些方法和Future
中的方法很相似:xxxxxxxxxx
val pro = Promise[Int] pro.success(42) pro.failure(new Exception("xxx Exception")) pro.complete(Failure(new Exception("xxx Exception")))还有一个
completeWith
,这个方法使得该Promise
的future
的完成状态和你传入的future
保持同步:xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21 + 21} val pro = Promise[Int] pro.completeWith(fut1)
Future
的filter
方法对Future
的结果进行校验,如果合法就原样保留;如果非法,则filter
返回的这个Future
就以NoSuchElementException
失败:xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21 + 21} val valid = fut1.filter( x => x > 0) // 合法的结果 valid.value // 返回 Some(Success(42)) val invalid = fut1.filter( x => x <0) // 非法的结果 invalid.value // 返回 Some(Failure(java.util.NoSuchElementException))另外,
Future
还提供了withFilter
方法,因此可以用for
表达式的过滤器来执行相同的操作:xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21 + 21} val valid = for (x <- fut1 if x >0) yield x // 合法的结果 valid.value // 返回 Some(Success(42)) val invalid = for (x <- fut1 if x <0) yield x // 非法的结果 invalid.value // 返回 Some(Failure(java.util.NoSuchElementException))Future
的collect
方法允许你在一次操作中同时完成校验和变换。如果传给
collect
方法的偏函数对Future
结果有定义,则collect
返回的Future
就会以经过该函数变换后的值成功完成。xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21 + 21} val valid = fut1 collect {case x if x >0 => x + 46} valid.value // 返回 Some(Success(88))如果传给
collect
方法的偏函数对Future
结果没有定义,则collect
返回的Future
就以NoSuchElementException
失败。xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21 + 21} val invalid = fut1 collect {case x if x < 0 => x + 46} valid.value // 返回 Some(Failure(java.util.NoSuchElementException))
2.2 处理失败
Scala
的Future
提供了处理失败的Future
的方式,包括:failed, fallbackTo, recover, recoverWith
。Future
的failed
方法将任何类型的失败的future
变换成一个成功的Future[Throwable]
,并带上引发失败的异常。xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/0} // 类型为 Future[Int] fut1.value // 返回 Some(Failure(java.lang.ArithmeticException)) val fut2 = fut1.failed // 类型为 Future[Throwable] fut2.value // 返回 Some(Success(java.lang.ArithmeticException))如果调用
failed
的Future
最终成功了,则failed
返回的这个Future
将以NoSuchElementException
失败。因此failed
方法只有在你预期某个future
一定会失败的情况下才适用。xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/1} // 类型为 Future[Int] fut1.value // 返回 Some(Success(21)) val fut2 = fut1.failed fut2.value // 返回 Some(Failure(java.util.NoSuchElementException))Future
的fallbackTo
方法允许你提供一个额外可选的Future
,这个新的Future
将用于在你调用fallbackTo
的那个Future
失败的情况。xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/0} val fut2 = Future{ Thread.sleep(10000); 21/1} val fut3 = fut1.fallbackTo(fut2) fut3.value // 返回 Some(Success(21))- 如果
fut1
成功,则fut1.fallbackTo(fut2)
返回fut1
。 - 如果
fut1
失败,而fut2
成功,则fut1.fallbackTo(fut2)
返回fut2
。 - 如果
fut1
失败,且fut2
失败,则fut1.fallbackTo(fut2)
返回fut1
。此时完全不考虑fut2
的失败。
xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/0} val fut2 = Future{ Thread.sleep(10000); assert(21 <0)} val fut3 = fut1.fallbackTo(fut2) fut3.value // 返回 Some(Failure(java.lang.ArithmeticException))- 如果
recover
方法让你把失败的future
变换成成功的future
,同时将成功的future
结果原样透传。xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/0} val fut2 = fut1 recover { case ex => -1 } fut2.value // 返回 Some(Success(-1))如果原始的
Future
没有失败,则recover
返回的这个Future
就会以相同的值完成:xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/1} val fut2 = fut1 recover { case ex => -1 } fut2.value // 返回 Some(Success(21))如果传给
recover
的偏函数没有对引发原始Future
最终失败的那个异常有定义,则原始的失败会被透传:xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/0} val fut2 = fut1 recover { case ex : IllegalArgumentException => -1 } fut2.value // 返回 Some(Failure(java.lang.ArithmeticException))recoverWith
方法和recover
很像,不过它并不是像recover
一样恢复成某个值,而是恢复成一个Future
:xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/0} val fut2 = fut1 recoverWith { case ex => Future{ Thread.sleep(10000); 21+21 } // 这里恢复成一个 Future,而不是一个值 } fut2.value // 返回 Some(Success(42))和
recover
一样,如果原始的Future
没有失败,则recoverWith
返回的这个Future
就会以相同的值完成:xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/1} val fut2 = fut1 recoverWith { case ex => Future{ Thread.sleep(10000); 21+21 } } fut2.value // 返回 Some(Success(21))和
recover
一样,如果传给recoverWih
的偏函数没有对引发原始Future
最终失败的那个异常有定义,则原始的失败会被透传:xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/0} val fut2 = fut1 recoverWith { case ex : IllegalArgumentException => Future{ Thread.sleep(10000); 21+21 } } fut2.value // 返回 Some(Failure(java.lang.ArithmeticException))
2.3 transform
Future
的transform
方法接收两个函数来对Future
进行变换:一个用于处理成功、另一个用于处理失败。xxxxxxxxxx
val factor = 1 val fut1 = Future{ Thread.sleep(10000); 21/factor} val fut2 = fut1.transform( x => x * -1, // 如果 fut1 成功,则调用这一行。此时 fut2 返回 Some(Success(-21)) ex => new Exception("exception because:",ex) // 如果 fut1 失败(例如 factor = 0时),则调用这一行,此时 fut2 返回 Some(Failure(java.lang.Exception)) )如果
fut1
成功了,则调用第一个函数;如果fut1
失败了,则调用第二个函数。注意:
transform
方法并不能将成功的Future
改变成失败的Future
,也不能将失败的Future
改变成成功的Future
。为了将成功的
Future
改变成失败的Future
,或者将失败的Future
改变成成功的Future
,Scala 2.12
引入了一个重载的transform
形式,接收一个从Try
到Try
的函数:xxxxxxxxxx
val factor = 1 val fut1 = Future{ Thread.sleep(10000); 21/factor} val fut2 = fut1.transform{ // 在 Scala 2.12 之后支持 case Success(x) => Success(x.abs + 1) case Failure(_) => Success(0) // 将 Failure 变换为 Success }
2.4 组合
Future
和它的伴生对象提供了用于组合多个Future
的方法。zip
方法将两个成功的Future
变换成这两个值的元组的Future
。xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/1} val fut2 = Future{ Thread.sleep(10000); 21+21} val fut3 = fit1.zip(fut2) // 一个 Future[(Int,Int)] 对象 fut3.value // 返回 Some(Success(21,42))如果任何一个
Future
失败了,zip
返回的这个Future
也会以相同的异常失败。xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/0} val fut2 = Future{ Thread.sleep(10000); 21+21} val fut3 = fit1.zip(fut2) // 一个 Future[(Int,Int)] 对象 fut3.value // 返回 Some(Failure(java.lang.ArithmeticException))如果两个
Future
都失败了,则zip
返回的是第一个Future
(也就是调用方)的那个异常。Future
伴生对象提供了一个fold
方法,用于累积一个TranserableOnce
集合中所有Future
的结果,并交出一个Future
的结果。如果集合中所有
Future
都成功了,则累积的Future
成功完成;如果集合中有任何一个Future
失败了,则累积的Future
失败,并且返回集合中首个失败的Future
的失败。xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/0} val fut2 = Future{ Thread.sleep(10000); 21+21} val fut3 = Future.fold(List(fut1,fut2))(0){ (acc, num) => acc + num }Future
伴生对象提供的reduce
方法和fold
方法都是一样的折叠操作,但是reduce
不需要提供初始值,而是用第一个Future
结果作为初始值。xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/0} val fut2 = Future{ Thread.sleep(10000); 21+21} val fut3 = Future.reduce(List(fut1,fut2)){ (acc, num) => acc + num }如果传入的集合为空,则没有第一个
Future
,此时reduce
将以NoSuchElementException
作为失败。Future.sequence
方法将一个TransversableOnece[Future]
集合变换成Future[TranversableOnece]
的Future
:xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/0} val fut2 = Future{ Thread.sleep(10000); 21+21} val list = List(fut1, fut2) // List[Future[Int]] val fut3 = Future.sequence(list) // Future[List[Int]]Future.traverse
方法会将任何元素类型的TranversableOnce
集合变成一个由Future
组成的TranversableOnce
,并将它sequence
成一个由值组成的TraversableOnce
的Future
:xxxxxxxxxx
val fut1 = Future.traverse(List(1,2,3)){i => Future(i)} fut1.value // Some(Success(1,2,3))
2.5 执行副作用
有可能你希望在执行完某个
Future
完成之后执行一个副作用(而不是返回一个新的Future
),为此Future
提供了好几种方法。最基本的方法是
foreach
,如果Future
成功则它会执行一个副作用。xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/0} val fut2 = Future{ Thread.sleep(10000); 21/1} fut1.foreach(x => println(x)) // fut1 执行失败,所以不会执行 println fut2.foreach(x => println(x)) // 当 fut2 执行成功的时候执行 println由于不带
yield
的for
会被编译器重写为对foreach
的调用,因此也可以通过for
表达式来达成同样的效果:xxxxxxxxxx
val fut1 = Future{ Thread.sleep(10000); 21/0} val fut2 = Future{ Thread.sleep(10000); 21/1} for (x <- fut1) println(x) for (y <- fut2) println(y)Future
还提供了方法来 “注册” 函数。onComplete
方法在Future
最终成功或失败时都会被执行。被注册的函数会被传入一个Try
对象(如果Future
成功了,那么就算一个包含结果的Success
;否则是一个包含失败原因的Failure
)。xxxxxxxxxx
import scala.util.{Success, Failure} val fut1 = Future{ Thread.sleep(10000); 21/1} fut1 onComplete { case Success(x) => println(x) case Failure(ex) => println(ex) }可以多次调用
Future.onComplete
来注册多个函数,但是onComplete
不能保证这些函数之间的执行顺序。如果你希望强制回调函数的顺序,则可以考虑使用Future.andThen
方法。Future.andThen
方法会返回一个新的Future
,这个新的Future
是对原始的Future
调用回调函数:xxxxxxxxxx
import scala.util.{Success, Failure} val fut1 = Future{ Thread.sleep(10000); 21/1} val fut2 = fut1 andThen { case Success(x) => println(x) case Failure(ex) => println(ex) }如果传入
adThen
的回调函数在执行时抛出异常,则这个异常是不会被传导到后续的adThen
,也不会体现在结果的Future
中。
2.6 Scala 2.12 中的新方法
scala 2.12
中添加的Future.flatten
方法将一个Future[Future[Int]]
变换成一个Future[Int]
。如:xxxxxxxxxx
val fut = Future{ Future{Thread.sleep(10000); 21/1} } // Future[Future[Int]] val fut1 = fut.flatten // Future[Int]scala 2.12
中添加的zipWith
方法将两个Future zip
到一起,然后在对结果的元组执行map
。xxxxxxxxxx
val fut1 = Future{ Future{Thread.sleep(10000); 21/1} } val fut2 = Future{ Future{Thread.sleep(10000); "hello world"} } val fut3 = fut1 zip fut2 // Future[(Int,String)] val fut4 = fut3 map{ // Future[String] case (num, str) => s"$num and $str" } fut4.value // 返回 Some(Success(21 and hello world))zipWith
允许你一步完成相同的操作:xxxxxxxxxx
val fut1 = Future{ Future{Thread.sleep(10000); 21/1} } val fut2 = Future{ Future{Thread.sleep(10000); "hello world"} } val fut4 = fut1.zipWith(fut2){ case (num, str) => s"$num and $str" } fut4.value // 返回 Some(Success(21 and hello world))scala 2.12
中还添加了transformWith
方法,可以用一个从Try
到Future
的函数对Future
进行变换。xxxxxxxxxx
val fut1 = Future{ Future{Thread.sleep(10000); 21/1} } val fut2 = fut1.transformWith{ case Success(res) => Future{ throw new Exception(res.toString)} case Failure(ex) => Future(0) }transformWith
方法和Future.transform
类似,但是transformWith
方法允许你交出Future
(相比较之下,transform
方法需要你交出Try
。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论