Task.Factory.FromAsync是否激发创建的任务
本文关键字:创建 任务 Factory FromAsync 是否 Task | 更新日期: 2023-09-27 18:24:17
我有两个任务t1
和t2
,它们是我从一个旧的API生成的,该API是用开始/结束异步模型设计的,如下所示。然而,严格地说,我想一个接一个地运行它们。(这是Azure表存储API)
Task<DataServiceResponse> t1 = Task.Factory.FromAsync(ctx1.BeginSaveChangesWithRetries(null, null), r => ctx1.EndSaveChangesWithRetries(r));
Task<DataServiceResponse> t2 = Task.Factory.FromAsync(ctx2.BeginSaveChangesWithRetries(null, null), r => ctx2.EndSaveChangesWithRetries(r));
await t1.ContinueWith(t => t2, TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.NotOnCanceled);
我阅读了FromAsync
文档,但它没有说明这些任务(t1
&t2
)是否被激发:
FromAsync(IAsyncResult, Action<IAsyncResult>):
创建一个任务,该任务在指定的IAsyncResult完成时执行结束方法操作。
- 这是否保证在成功执行
t1
之后始终执行t2
- 我相信这段代码调用了开始/结束对的
Begin...
方法。通常情况下,操作(在这种情况下,向Azure服务发出HTTP请求)是在最终方法中完成的吗?(我不太熟悉begin/end实现内部的内容) t1
是否在await
语句之前开始(或计划)(就像我使用Task.Factory.StartNew
一样)
要比"不,它不会做你想做的事"更明确地回答:
Task.Factory.FromAsync是否激发创建的任务?
是的,Task
对象是完全功能性的,并且将执行它的设计任务——等待已经运行的请求结束。
这个保证t2是否总是在成功执行t1之后执行?
不,网络请求已经在运行/超出我们的控制范围,您可以对其进行定义/订购。
FormAsync
创建的任务不能单独启动。它们接收IAsyncResult
作为参数,因此您已经通过调用BeginSaveChangesWithRetries
启动了底层作业/任务/web请求。这里的任务只是这个遗留异步机制的包装器,它允许您等待这些任务,并以新的、好的方式编写代码。
要做到这一点,简单地写:
await Task.Factory.FromAsync(ctx1.BeginSaveChangesWithRetries(null, null), r => ctx1.EndSaveChangesWithRetries(r));
await Task.Factory.FromAsync(ctx2.BeginSaveChangesWithRetries(null, null), r => ctx2.EndSaveChangesWithRetries(r));
如果第一次等待投球,那么第二次就不会被执行。
标题问题的答案是肯定的,一个新的任务开始了,正如使用Resharper的反编译器和.NET参考源所发现的那样,但你永远看不到它。
FromAsync创建一个内部分离的Task,以便在其TaskScheduler上同步运行End方法。您从未见过此任务。您看到的是一个TaskCompletionSource.Task,当End方法正常完成或抛出异常时,它会发出信号。
End方法引发的异常设置在TaskCompletionSource上,因此也设置在您等待的Task上。
从FromAsync返回的Task是由TaskCompletionSource创建的,所以你不能说它是否启动了——当你的操作完成时,它可以被等待并发出信号
因此:
T2将仅在成功完成时运行
- T2是在您调用ContinueWith方法之前启动的,因此T1和T2将并行运行。只有在T1成功的情况下才会等待T2
- Begin/End内部发生的情况取决于实现,但通常Begin会启动异步操作,End会阻止等待此操作的结果。Web服务和WebClient调用就是这样工作的
- T1在调用Begin方法时开始,该方法发生在第一行
编辑
如果您调用接受函数而不是IAsyncResult的FromAsync重载,情况不会改变,因为FromAsync立即调用函数并启动操作