在我们业务操作时,难免会有多次操作,我们期望什么结果呢?
绝大部分情况,应该是只需要最后一次操作的结果,其它操作应该无效。
自定义等待的任务类
1. 可等待的任务类 AwaitableTask:

1 ///2 /// 可等待的任务 3 /// 4 public class AwaitableTask 5 { 6 /// 7 /// 获取任务是否为不可执行状态 8 /// 9 public bool NotExecutable { get; private set; } 10 11 /// 12 /// 设置任务不可执行 13 /// 14 public void SetNotExecutable() 15 { 16 NotExecutable = true; 17 } 18 19 /// 20 /// 获取任务是否有效 21 /// 注:对无效任务,可以不做处理。减少并发操作导致的干扰 22 /// 23 public bool IsInvalid { get; private set; } = true; 24 25 /// 26 /// 标记任务无效 27 /// 28 public void MarkTaskValid() 29 { 30 IsInvalid = false; 31 } 32 33 #region Task 34 35 private readonly Task _task; 36 /// 37 /// 初始化可等待的任务。 38 /// 39 /// 40 public AwaitableTask(Task task) => _task = task; 41 42 /// 43 /// 获取任务是否已完成 44 /// 45 public bool IsCompleted => _task.IsCompleted; 46 47 /// 48 /// 任务的Id 49 /// 50 public int TaskId => _task.Id; 51 52 /// 53 /// 开始任务 54 /// 55 public void Start() => _task.Start(); 56 57 /// 58 /// 同步执行开始任务 59 /// 60 public void RunSynchronously() => _task.RunSynchronously(); 61 62 #endregion 63 64 #region TaskAwaiter 65 66 /// 67 /// 获取任务等待器 68 /// 69 /// 70 public TaskAwaiter GetAwaiter() => new TaskAwaiter(this); 71 72 /// Provides an object that waits for the completion of an asynchronous task. 73 [HostProtection(SecurityAction.LinkDemand, ExternalThreading = true, Synchronization = true)] 74 public struct TaskAwaiter : INotifyCompletion 75 { 76 private readonly AwaitableTask _task; 77 78 /// 79 /// 任务等待器 80 /// 81 /// 82 public TaskAwaiter(AwaitableTask awaitableTask) => _task = awaitableTask; 83 84 /// 85 /// 任务是否完成. 86 /// 87 public bool IsCompleted => _task._task.IsCompleted; 88 89 /// 90 public void OnCompleted(Action continuation) 91 { 92 var This = this; 93 _task._task.ContinueWith(t => 94 { 95 if (!This._task.NotExecutable) continuation?.Invoke(); 96 }); 97 } 98 /// 99 /// 获取任务结果 100 /// 101 public void GetResult() => _task._task.Wait(); 102 } 103 104 #endregion 105 106 }
无效的操作可以分为以下俩种:
- 已经进行中的操作,后续结果应标记为无效
- 还没开始的操作,后续不执行
自定义任务类型 AwaitableTask中,添加俩个字段NotExecutable、IsInvalid:
1 ///2 /// 获取任务是否为不可执行状态 3 /// 4 public bool NotExecutable { get; private set; } 5 /// 6 /// 获取任务是否有效 7 /// 注:对无效任务,可以不做处理。减少并发操作导致的干扰 8 /// 9 public bool IsInvalid { get; private set; } = true;
2. 有返回结果的可等待任务类 AwaitableTask

1 ///2 /// 可等待的任务 3 /// 4 /// 5 public class AwaitableTask : AwaitableTask 6 { 7 private readonly Task _task; 8 /// 9 /// 初始化可等待的任务 10 /// 11 /// 需要执行的任务 12 public AwaitableTask(Task task) : base(task) => _task = task; 13 14 #region TaskAwaiter 15 16 /// 17 /// 获取任务等待器 18 /// 19 /// 20 public new TaskAwaiter GetAwaiter() => new TaskAwaiter(this); 21 22 /// 23 /// 任务等待器 24 /// 25 [HostProtection(SecurityAction.LinkDemand, ExternalThreading = true, Synchronization = true)] 26 public new struct TaskAwaiter : INotifyCompletion 27 { 28 private readonly AwaitableTask _task; 29 30 /// 31 /// 初始化任务等待器 32 /// 33 /// 34 public TaskAwaiter(AwaitableTask awaitableTask) => _task = awaitableTask; 35 36 /// 37 /// 任务是否已完成。 38 /// 39 public bool IsCompleted => _task._task.IsCompleted; 40 41 /// 42 public void OnCompleted(Action continuation) 43 { 44 var This = this; 45 _task._task.ContinueWith(t => 46 { 47 if (!This._task.NotExecutable) continuation?.Invoke(); 48 }); 49 } 50 51 /// 52 /// 获取任务结果。 53 /// 54 /// 55 public TResult GetResult() => _task._task.Result; 56 } 57 58 #endregion 59 }
添加任务等待器,同步等待结果返回:
1 ///2 /// 获取任务等待器 3 /// 4 /// 5 public new TaskAwaiter GetAwaiter() => new TaskAwaiter(this); 6 7 /// 8 /// 任务等待器 9 /// 10 [HostProtection(SecurityAction.LinkDemand, ExternalThreading = true, Synchronization = true)] 11 public new struct TaskAwaiter : INotifyCompletion 12 { 13 private readonly AwaitableTask _task; 14 15 /// 16 /// 初始化任务等待器 17 /// 18 /// 19 public TaskAwaiter(AwaitableTask awaitableTask) => _task = awaitableTask; 20 21 /// 22 /// 任务是否已完成。 23 /// 24 public bool IsCompleted => _task._task.IsCompleted; 25 26 /// 27 public void OnCompleted(Action continuation) 28 { 29 var This = this; 30 _task._task.ContinueWith(t => 31 { 32 if (!This._task.NotExecutable) continuation?.Invoke(); 33 }); 34 } 35 36 /// 37 /// 获取任务结果。 38 /// 39 /// 40 public TResult GetResult() => _task._task.Result; 41 }
异步任务队列
添加异步任务队列类,用于任务的管理,如添加、执行、筛选等:
1. 自动取消之前的任务 AutoCancelPreviousTask
内部使用线程,循环获取当前任务列表,如果当前任务被标记NotExecutable不可执行,则跳过。
NotExecutable是何时标记的?
获取任务时,标记所有获取的任务为NotExecutable。直到任务列表中为空,那么只执行最后获取的一个任务。
2. 标记已经进行的任务无效 MarkTaskValid
当前进行的任务,无法中止,那么标记为无效即可。
1 ///2 /// 上一次异步操作 3 /// 4 private AwaitableTask _lastDoingTask; 5 private bool TryGetNextTask(out AwaitableTask task) 6 { 7 task = null; 8 while (_queue.Count > 0) 9 { 10 //获取并从队列中移除任务 11 if (_queue.TryDequeue(out task) && (!AutoCancelPreviousTask || _queue.Count == 0)) 12 { 13 //设置进行中的异步操作无效 14 _lastDoingTask?.MarkTaskValid(); 15 _lastDoingTask = task; 16 return true; 17 } 18 //并发操作,设置任务不可执行 19 task.SetNotExecutable(); 20 } 21 return false; 22 }
后续执行完后,根据此标记,设置操作结果为空。
1 ///2 /// 执行异步操作 3 /// 4 /// 返回结果类型 5 /// 异步操作 6 /// isInvalid:异步操作是否有效;result:异步操作结果 7 public async Task<(bool isInvalid, T reslut)> ExecuteAsync (Func > func) 8 { 9 var task = GetExecutableTask(func); 10 var result = await await task; 11 if (!task.IsInvalid) 12 { 13 result = default(T); 14 } 15 return (task.IsInvalid, result); 16 }
实践测试
启动10个并发任务,测试实际的任务队列并发操作管理:
1 public MainWindow() 2 { 3 InitializeComponent(); 4 _asyncTaskQueue = new AsyncTaskQueue 5 { 6 AutoCancelPreviousTask = true, 7 UseSingleThread = true 8 }; 9 } 10 private AsyncTaskQueue _asyncTaskQueue; 11 private void ButtonBase_OnClick(object sender, RoutedEventArgs e) 12 { 13 // 快速启动10个任务 14 for (var i = 1; i < 10; i++) 15 { 16 Test(_asyncTaskQueue, i); 17 } 18 } 19 public static async void Test(AsyncTaskQueue taskQueue, int num) 20 { 21 var result = await taskQueue.ExecuteAsync(async () => 22 { 23 Debug.WriteLine("输入:" + num); 24 // 长时间耗时任务 25 await Task.Delay(TimeSpan.FromSeconds(5)); 26 return num * 100; 27 }); 28 Debug.WriteLine($"{num}输出的:" + result); 29 }
测试结果如下:
一共9次操作,只有最后一次操作结果,才是有效的。其它8次操作,一次是无效的,7次操作被取消不执行。