【多线程笔记】任务-TaskCompletionSource

简介

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("执行完成");
posted @ 2019-12-08 19:30  .Neterr  阅读(2985)  评论(1编辑  收藏  举报