TaskCompletionSource的使用场景

Posted schyzhkj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TaskCompletionSource的使用场景相关的知识,希望对你有一定的参考价值。

 

Task类最适合表示计算密集型操作。默认地,为了提供有效的执行操作,它利用了.Net线程池中特殊的支持,同时也对异步计算何时,何地,如何执行提供了大量的控制。

生成计算受限的tasks有几种方法。

  1. 在.Net 4中,启动一个新的计算受限的task的主要方法是TaskFactory.StartNew(),该方法接受一个异步执行的委托(一般来说是一个Action或者一个Func<TResult>)。如果提供了一个Action,返回的Task就代表那个委托的异步执行操作。如果提供了一个Func<TResult>,就会返回一个Task<TResult>。存在StartNew()的重载,该重载接受CancellationToken,TaskCreationOptions,和TaskScheduler,这些都对task的调度和执行提供了细粒度的控制。作用在当前调度者的工厂实例可以作为Task类的静态属性,例如Task.Factory.StartNew()。
  2. 在.Net 4.5中,Task类型暴露了一个静态的Run方法作为一个StartNew方法的捷径,可以很轻松地使用它来启动一个作用在线程池上的计算受限的task。从.Net 4.5开始,对于启动一个计算受限的task,这是一个更受人喜欢的机制。当行为要求更多的细粒度控制时,才直接使用StartNew。
  3. Task类型公开了构造函数和Start方法。如果必须要有分离自调度的构造函数,这些就是可以使用的(正如先前提到的,公开的APIs必须只返回已经启动的tasks)。
  4. Task类型公开了多个ContinueWith的重载。当另外一个task完成的时候,该方法会创建新的将被调度的task。该重载接受CancellationToken,TaskCreationOptions,和TaskScheduler,这些都对task的调度和执行提供了细粒度的控制。
  5. TaskFactory类提供了ContinueWhenAll 和ContinueWhenAny方法。当提供的一系列的tasks中的所有或任何一个完成时,这些方法会创建一个即将被调度的新的task。有了ContinueWith,就有了对于调度的控制和任务的执行的支持。  

 

        TaskCompletionSource生成Task的另一种方法.使用TaskCompletionSource很简单,只需要实例化它即可。TaskCompletionSource有一个Task属性,你可以对该属性暴露的task做操作,比如让它wait或者ContinueWith等操作。当然,这个task由TaskCompletionSource完全控制,相当于你可以对创建的Task提前做适当控制规则。

 

      使用TaskCompletionSource<TResult>类型创建的Tasks不应该直接被全部执行的线程返回。TaskCompletionSource<TResult>暴露了一个返回相关的Task<TResult>实例的Task属性。该task的生命周期通过TaskCompletionSource<TResult>实例暴露的方法控制,换句话说,这些实例包括SetResult, SetException, SetCanceled, 和它们的TrySet* 变量。

 

      你可以使用临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphores)和事件(Event)来处理线程同步。然而,在编写一些异步处理函数,尤其是还有 async 和 await 使用的时候,还有一些更方便的类型可以用来处理线程同步。

使用 TaskCompletionSource ,你可以轻松地编写既可以异步等待,又可以同步等待的代码来。 

 

public class WalterlvDemo
{
    private readonly TaskCompletionSource<object> _source = new TaskCompletionSource<object>();

    public Task WaitAsync() => _source.Task;

    public void Wait() => _source.Task.GetAwaiter().GetResult();
}

var demo = new
WalterlvDemo();

等待时可以同步:  demo.Wait();

也可以异步:         await demo.WaitAsync();

而同步的那个方法,便可以用来做线程同步使用。

 

要像一个事件一样让同步等待阻塞着的线程继续跑起来,则需要设置这个事件。

TaskCompletionSource<object> 提供了很多让任务完成的方法: 

技术图片

 

 

 可以通过让这个 TaskCompletionSource<object> 完成、取消或设置异常的方式让这个 Task 进入完成、取消或错误状态,然后等待它的线程就会继续执行;当然如果有异常,就会让等待的线程收到一个需要处理的异常。

_source.SetResult(null);

以上是关于TaskCompletionSource的使用场景的主要内容,如果未能解决你的问题,请参考以下文章

C# 之 多线程 -- 任务概念以及使用示例 ( Task | TaskCompletionSource | Async | Await )

Task FromResult vs TaskCompletionSource SetResult

csharp csharp_test_taskcompletionsource_and_threads.cs

CefGlue获取网页源代码

Monotouch 应用程序中的线程数

如何防止任务的同步延续?