简介
TaskCompletionSource生成Task的另一种方法.使用TaskCompletionSource很简单,只需要实例化它即可。TaskCompletionSource有一个Task属性,你可以对该属性暴露的task做操作,比如让它wait或者ContinueWith等操作。当然,这个task由TaskCompletionSource完全控制。
属性
属性 |
说明 |
Task |
获取由此 Task 创建的 TaskCompletionSource。 |
方法
方法 |
说明 |
SetCanceled() |
将基础 Task 转换为 Canceled 状态。 |
SetException(Exception) |
将基础 Task 转换为 Faulted 状态,并将其绑定到一个指定异常上。 |
SetException(IEnumerable) |
将基础 Task 转换为 Faulted 状态,并对其绑定一些异常对象。 |
SetResult(TResult) |
将基础 Task 转换为 RanToCompletion 状态。 |
TrySetCanceled() |
尝试将基础 Task 转换为 Canceled 状态。 |
TrySetCanceled(CancellationToken) |
尝试将基础 Task 转换为 Canceled 状态并启用要存储在取消的任务中的取消标记。 |
TrySetException(Exception) |
尝试将基础 Task 转换为 Faulted 状态,并将其绑定到一个指定异常上。 |
TrySetException(IEnumerable) |
尝试将基础 Task 转换为 Faulted 状态,并对其绑定一些异常对象。 |
TrySetResult(TResult) |
尝试将基础 Task 转换为 RanToCompletion 状态。 |
案例
使用模拟一个Task.Run()
public static Task<TResult> Run<TResult>(Func<TResult> func)
{
TaskCompletionSource<TResult> tcs = new TaskCompletionSource<TResult>();
var t = new Thread(() => {
try
{
tcs.SetResult( func());
}
catch (Exception ex)
{
tcs.SetException(ex);
}
});
t.IsBackground = true;
t.Start();
return tcs.Task;
}
封装回调方式的异步处理
class Program
{
static void Main(string[] args)
{
var t = EventWrap();
Console.WriteLine(t.Result);
Console.ReadKey();
}
static Task<string> EventWrap()
{
var tcs = new TaskCompletionSource<string>();
var eventClass = new EventClass();
eventClass.Done += (args) => {
tcs.SetResult(args); };
return tcs.Task;
}
}
public class EventClass
{
public EventClass()
{
Task.Delay(2000).ContinueWith(t =>this.Do());
}
public Action<string> Done = (args) => { };
public void Do()
{
Done("Done");
}
}
可指定处理线程数的异步任务队列:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication6
{
public class PCQueue : IDisposable
{
class WorkItem
{
public readonly TaskCompletionSource<object> TaskSource;
public readonly Action Action;
public readonly CancellationToken? CancelToken;
public WorkItem(
TaskCompletionSource<object> taskSource,
Action action,
CancellationToken? cancelToken)
{
TaskSource = taskSource;
Action = action;
CancelToken = cancelToken;
}
}
BlockingCollection<WorkItem> _taskQ = new BlockingCollection<WorkItem>();
/// <summary>
/// 为每个消费者创建并启动单独的任务: 这里我启动了2个任务,用于打印easy和easy2这两个的顺序不一定
/// </summary>
/// <param name="workerCount"></param>
public PCQueue(int workerCount)
{
// 为每个消费者创建并启动单独的任务:
for (int i = 0; i < workerCount; i++)
Task.Factory.StartNew(Consume);
}
public void Dispose() { _taskQ.CompleteAdding(); }
/// <summary>
/// 默认任务取消标识为null的任务进队方法
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public Task EnqueueTask(Action action)
{
return EnqueueTask(action, null);
}
/// <summary>
/// 任务进队方法含标识
/// </summary>
/// <param name="action"></param>
/// <param name="cancelToken"></param>
/// <returns></returns>
public Task EnqueueTask(Action action, CancellationToken? cancelToken)
{
var tcs = new TaskCompletionSource<object>();
_taskQ.Add(new WorkItem(tcs, action, cancelToken));
//通过TaskCompletionSource返回任务本身,可查看任务的响应信息如result,exception,status等等
return tcs.Task;
}
void Consume()
{
foreach (WorkItem workItem in _taskQ.GetConsumingEnumerable())
if (workItem.CancelToken.HasValue &&
workItem.CancelToken.Value.IsCancellationRequested)
{
workItem.TaskSource.SetCanceled();
}
else
try
{
workItem.Action();
workItem.TaskSource.SetResult(1234); // 表示完成
}
catch (OperationCanceledException ex)
{
if (ex.CancellationToken == workItem.CancelToken)
workItem.TaskSource.SetCanceled();
else
workItem.TaskSource.SetException(ex);
}
catch (Exception ex)
{
workItem.TaskSource.SetException(ex);
}
}
}
class Program
{
static void Main(string[] args)
{
CancellationToken token1 = new CancellationToken(true);
//
var pcQ = new PCQueue(2);
Task task = pcQ.EnqueueTask(() => Console.WriteLine("Easy!"),token1);//输出easy的任务不会执行
task = pcQ.EnqueueTask(() => Console.WriteLine("Easy2!"));//会执行
// ...
Console.Read();
}
}
}
案例
var waitForStop = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
CancellationTokenSource source = new CancellationTokenSource();
Console.WriteLine("3秒后取消");
Task.Delay(3000).ContinueWith(t => source.Cancel());
source.Token.Register(state =>
{
var tcs = (TaskCompletionSource<object>)state;
tcs.TrySetResult(null);
}, waitForStop);
Console.WriteLine("正在执行");
await waitForStop.Task;
Console.WriteLine("执行完成");