我试图了解TaskCompletionSource
的目的及其与异步/无线程工作的关系。我想我有一般的想法,但我想确保我的理解是正确的。
我首先开始研究任务并行库(TPL),以确定是否有一种很好的方法来创建自己的无线/异步工作(比如说你试图提高ASP.NET站点的可伸缩性)以及理解TPL看起来将来会非常重要(async
/ await
)。这让我想到了TaskCompletionSource
。
根据我的理解,将TaskCompletionSource
添加到您的某个类中似乎并没有真正做到使您的编码异步;如果您仍在执行同步代码,则对代码的调用将被阻止。我认为微软API也是如此。例如,在DownloadStringTaskAsync
类的WebClient
之内,最初他们正在执行的任何设置/同步代码都将被阻止。您正在执行的代码必须在某个线程上运行,无论是当前线程还是您必须分拆一个新线程。
因此,当您从Microsoft调用其他TaskCompletionSource
调用时,在自己的代码中使用async
,这样您的类的客户端就不必为您的类创建一个新线程来阻止
不确定Microsoft如何在内部执行异步API。例如,对于.Net 4.5,async
有一个新的SqlDataReader
方法。我知道有IO完成端口。我认为这可能是大多数C#开发人员不会使用的低级抽象(C ++?)。不确定IO完成端口是否适用于数据库或网络调用(HTTP),或者它是否仅用于文件IO。
所以问题是,我理解正确吗?是否有某些我错误表示的内容?
答案 0 :(得分:58)
TaskCompletionSource
用于创建不执行代码的Task
个对象。
微软新的异步API使用它们很多 - 任何时候都有基于I / O的异步操作(或其他非基于CPU的异步操作,如超时)。此外,您编写的任何async Task
方法都将使用TCS完成其返回的Task
。
我有一篇博文Creating Tasks,讨论了创建Task
个实例的不同方法。它是从async
/ await
角度(不是TPL角度)编写的,但它仍然适用于此。
另见Stephen Toub的优秀帖子:
TaskCompletionSource
至await
任何内容)。Begin
创建End
/ TaskCompletionSource
。)答案 1 :(得分:5)
我喜欢http://tutorials.csharp-online.net/TaskCompletionSource
中提供的解释(对不起,链接可能已经死了)
前两段如下
我们已经看到Task.Run如何创建一个在一个上运行委托的任务 汇集(或非汇集)线程。另一种创建任务的方法是 TaskCompletionSource。
TaskCompletionSource允许您从任何操作中创建任务 一段时间后开始并结束。它的工作原理是给你一个“奴隶” 您手动驱动的任务 - 指示操作何时完成 或者是错误。这是I / O绑定工作的理想选择:您可以获得所有好处 任务(具有传播返回值的能力,异常, 和持续)在没有阻塞线程的持续时间 操作
要使用TaskCompletionSource,您只需实例化该类。它 公开一个Task属性,该属性返回您可以等待的任务 并附加延续 - 就像任何其他任务一样。任务, 但是,完全由TaskCompletionSource对象控制 以下方法:
public class TaskCompletionSource<TResult>
{
public void SetResult(TResult result);
public void SetException (Exception exception);
public void SetCanceled();
public bool TrySetResult (TResult result);
public bool TrySetException (Exception exception);
public bool TrySetCanceled();
...
}
调用这些方法中的任何一个都会发出任务信号,并将其放入 完成,故障或取消状态(我们将覆盖后者 “取消”部分。你应该调用其中一种方法 恰好一次:如果再次调用,则为SetResult,SetException或SetCanceled 将抛出异常,而Try *方法返回false。
以下示例在等待五秒后打印42:
var tcs = new TaskCompletionSource<int>();
new Thread (() => {
Thread.Sleep (5000);
tcs.SetResult (42);
})
.Start();
Task<int> task = tcs.Task; // Our "slave" task.
Console.WriteLine(task.Result); // 42
其他有趣的引语
TaskCompletionSource的真正强大之处在于创建不能完成的任务 捆绑线程。
..以及稍后
我们在没有线程的情况下使用TaskCompletionSource意味着一个线程 只有在继续开始时才会使用,五秒钟后。我们 可以通过一次启动10,000个这样的操作来证明这一点 没有错误或资源消耗过多: