C# 异步并发操作,只保留最后一次操作
在我们业务操作时,难免会有多次操作,我们期望什么结果呢?
绝大部分情况,应该是只需要最后一次操作的结果,其它操作应该无效。
自定义等待的任务类
1. 可等待的任务类 AwaitableTask:
/// <summary>
/// 可等待的任务
/// </summary>
public class AwaitableTask
{
/// <summary>
/// 获取任务是否为不可执行状态
/// </summary>
public bool NotExecutable { get; private set; } /// <summary>
/// 设置任务不可执行
/// </summary>
public void SetNotExecutable()
{
NotExecutable = true;
} /// <summary>
/// 获取任务是否有效
/// 注:对无效任务,可以不做处理。减少并发操作导致的干扰
/// </summary>
public bool IsInvalid { get; private set; } = true; /// <summary>
/// 标记任务无效
/// </summary>
public void MarkTaskValid()
{
IsInvalid = false;
} #region Task private readonly Task _task;
/// <summary>
/// 初始化可等待的任务。
/// </summary>
/// <param name="task"></param>
public AwaitableTask(Task task) => _task = task; /// <summary>
/// 获取任务是否已完成
/// </summary>
public bool IsCompleted => _task.IsCompleted; /// <summary>
/// 任务的Id
/// </summary>
public int TaskId => _task.Id; /// <summary>
/// 开始任务
/// </summary>
public void Start() => _task.Start(); /// <summary>
/// 同步执行开始任务
/// </summary>
public void RunSynchronously() => _task.RunSynchronously(); #endregion #region TaskAwaiter /// <summary>
/// 获取任务等待器
/// </summary>
/// <returns></returns>
public TaskAwaiter GetAwaiter() => new TaskAwaiter(this); /// <summary>Provides an object that waits for the completion of an asynchronous task. </summary>
[HostProtection(SecurityAction.LinkDemand, ExternalThreading = true, Synchronization = true)]
public struct TaskAwaiter : INotifyCompletion
{
private readonly AwaitableTask _task; /// <summary>
/// 任务等待器
/// </summary>
/// <param name="awaitableTask"></param>
public TaskAwaiter(AwaitableTask awaitableTask) => _task = awaitableTask; /// <summary>
/// 任务是否完成.
/// </summary>
public bool IsCompleted => _task._task.IsCompleted; /// <inheritdoc />
public void OnCompleted(Action continuation)
{
var This = this;
_task._task.ContinueWith(t =>
{
if (!This._task.NotExecutable) continuation?.Invoke();
});
}
/// <summary>
/// 获取任务结果
/// </summary>
public void GetResult() => _task._task.Wait();
} #endregion }
无效的操作可以分为以下俩种:
- 已经进行中的操作,后续结果应标记为无效
- 还没开始的操作,后续不执行
自定义任务类型 AwaitableTask中,添加俩个字段NotExecutable、IsInvalid:
/// <summary>
/// 获取任务是否为不可执行状态
/// </summary>
public bool NotExecutable { get; private set; }
/// <summary>
/// 获取任务是否有效
/// 注:对无效任务,可以不做处理。减少并发操作导致的干扰
/// </summary>
public bool IsInvalid { get; private set; } = true;
2. 有返回结果的可等待任务类 AwaitableTask<TResult>:
/// <summary>
/// 可等待的任务
/// </summary>
/// <typeparam name="TResult"></typeparam>
public class AwaitableTask<TResult> : AwaitableTask
{
private readonly Task<TResult> _task;
/// <summary>
/// 初始化可等待的任务
/// </summary>
/// <param name="task">需要执行的任务</param>
public AwaitableTask(Task<TResult> task) : base(task) => _task = task; #region TaskAwaiter /// <summary>
/// 获取任务等待器
/// </summary>
/// <returns></returns>
public new TaskAwaiter GetAwaiter() => new TaskAwaiter(this); /// <summary>
/// 任务等待器
/// </summary>
[HostProtection(SecurityAction.LinkDemand, ExternalThreading = true, Synchronization = true)]
public new struct TaskAwaiter : INotifyCompletion
{
private readonly AwaitableTask<TResult> _task; /// <summary>
/// 初始化任务等待器
/// </summary>
/// <param name="awaitableTask"></param>
public TaskAwaiter(AwaitableTask<TResult> awaitableTask) => _task = awaitableTask; /// <summary>
/// 任务是否已完成。
/// </summary>
public bool IsCompleted => _task._task.IsCompleted; /// <inheritdoc />
public void OnCompleted(Action continuation)
{
var This = this;
_task._task.ContinueWith(t =>
{
if (!This._task.NotExecutable) continuation?.Invoke();
});
} /// <summary>
/// 获取任务结果。
/// </summary>
/// <returns></returns>
public TResult GetResult() => _task._task.Result;
} #endregion
}
添加任务等待器,同步等待结果返回:
/// <summary>
/// 获取任务等待器
/// </summary>
/// <returns></returns>
public new TaskAwaiter GetAwaiter() => new TaskAwaiter(this); /// <summary>
/// 任务等待器
/// </summary>
[HostProtection(SecurityAction.LinkDemand, ExternalThreading = true, Synchronization = true)]
public new struct TaskAwaiter : INotifyCompletion
{
private readonly AwaitableTask<TResult> _task; /// <summary>
/// 初始化任务等待器
/// </summary>
/// <param name="awaitableTask"></param>
public TaskAwaiter(AwaitableTask<TResult> awaitableTask) => _task = awaitableTask; /// <summary>
/// 任务是否已完成。
/// </summary>
public bool IsCompleted => _task._task.IsCompleted; /// <inheritdoc />
public void OnCompleted(Action continuation)
{
var This = this;
_task._task.ContinueWith(t =>
{
if (!This._task.NotExecutable) continuation?.Invoke();
});
} /// <summary>
/// 获取任务结果。
/// </summary>
/// <returns></returns>
public TResult GetResult() => _task._task.Result;
}
异步任务队列
/// <summary>
/// 异步任务队列
/// </summary>
public class AsyncTaskQueue : IDisposable
{
/// <summary>
/// 异步任务队列
/// </summary>
public AsyncTaskQueue()
{
_autoResetEvent = new AutoResetEvent(false);
_thread = new Thread(InternalRunning) { IsBackground = true };
_thread.Start();
} #region 执行 /// <summary>
/// 执行异步操作
/// </summary>
/// <typeparam name="T">返回结果类型</typeparam>
/// <param name="func">异步操作</param>
/// <returns>isInvalid:异步操作是否有效;result:异步操作结果</returns>
public async Task<(bool isInvalid, T reslut)> ExecuteAsync<T>(Func<Task<T>> func)
{
var task = GetExecutableTask(func);
var result = await await task;
if (!task.IsInvalid)
{
result = default(T);
}
return (task.IsInvalid, result);
} /// <summary>
/// 执行异步操作
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <returns></returns>
public async Task<bool> ExecuteAsync<T>(Func<Task> func)
{
var task = GetExecutableTask(func);
await await task;
return task.IsInvalid;
} #endregion #region 添加任务 /// <summary>
/// 获取待执行任务
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
private AwaitableTask GetExecutableTask(Action action)
{
var awaitableTask = new AwaitableTask(new Task(action));
AddPenddingTaskToQueue(awaitableTask);
return awaitableTask;
} /// <summary>
/// 获取待执行任务
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="function"></param>
/// <returns></returns>
private AwaitableTask<TResult> GetExecutableTask<TResult>(Func<TResult> function)
{
var awaitableTask = new AwaitableTask<TResult>(new Task<TResult>(function));
AddPenddingTaskToQueue(awaitableTask);
return awaitableTask;
} /// <summary>
/// 添加待执行任务到队列
/// </summary>
/// <param name="task"></param>
/// <returns></returns>
private void AddPenddingTaskToQueue(AwaitableTask task)
{
//添加队列,加锁。
lock (_queue)
{
_queue.Enqueue(task);
//开始执行任务
_autoResetEvent.Set();
}
} #endregion #region 内部运行 private void InternalRunning()
{
while (!_isDisposed)
{
if (_queue.Count == )
{
//等待后续任务
_autoResetEvent.WaitOne();
}
while (TryGetNextTask(out var task))
{
//如已从队列中删除
if (task.NotExecutable) continue; if (UseSingleThread)
{
task.RunSynchronously();
}
else
{
task.Start();
}
}
}
}
/// <summary>
/// 上一次异步操作
/// </summary>
private AwaitableTask _lastDoingTask;
private bool TryGetNextTask(out AwaitableTask task)
{
task = null;
while (_queue.Count > )
{
//获取并从队列中移除任务
if (_queue.TryDequeue(out task) && (!AutoCancelPreviousTask || _queue.Count == ))
{
//设置进行中的异步操作无效
_lastDoingTask?.MarkTaskValid();
_lastDoingTask = task;
return true;
}
//并发操作,设置任务不可执行
task.SetNotExecutable();
}
return false;
} #endregion #region dispose /// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
} /// <summary>
/// 析构任务队列
/// </summary>
~AsyncTaskQueue() => Dispose(false); private void Dispose(bool disposing)
{
if (_isDisposed) return;
if (disposing)
{
_autoResetEvent.Dispose();
}
_thread = null;
_autoResetEvent = null;
_isDisposed = true;
} #endregion #region 属性及字段 /// <summary>
/// 是否使用单线程完成任务.
/// </summary>
public bool UseSingleThread { get; set; } = true; /// <summary>
/// 自动取消以前的任务。
/// </summary>
public bool AutoCancelPreviousTask { get; set; } = false; private bool _isDisposed;
private readonly ConcurrentQueue<AwaitableTask> _queue = new ConcurrentQueue<AwaitableTask>();
private Thread _thread;
private AutoResetEvent _autoResetEvent; #endregion
添加异步任务队列类,用于任务的管理,如添加、执行、筛选等:
1. 自动取消之前的任务 AutoCancelPreviousTask
内部使用线程,循环获取当前任务列表,如果当前任务被标记NotExecutable不可执行,则跳过。
NotExecutable是何时标记的?
获取任务时,标记所有获取的任务为NotExecutable。直到任务列表中为空,那么只执行最后获取的一个任务。
2. 标记已经进行的任务无效 MarkTaskValid
当前进行的任务,无法中止,那么标记为无效即可。
/// <summary>
/// 上一次异步操作
/// </summary>
private AwaitableTask _lastDoingTask;
private bool TryGetNextTask(out AwaitableTask task)
{
task = null;
while (_queue.Count > )
{
//获取并从队列中移除任务
if (_queue.TryDequeue(out task) && (!AutoCancelPreviousTask || _queue.Count == ))
{
//设置进行中的异步操作无效
_lastDoingTask?.MarkTaskValid();
_lastDoingTask = task;
return true;
}
//并发操作,设置任务不可执行
task.SetNotExecutable();
}
return false;
}
后续执行完后,根据此标记,设置操作结果为空。
/// <summary>
/// 执行异步操作
/// </summary>
/// <typeparam name="T">返回结果类型</typeparam>
/// <param name="func">异步操作</param>
/// <returns>isInvalid:异步操作是否有效;result:异步操作结果</returns>
public async Task<(bool isInvalid, T reslut)> ExecuteAsync<T>(Func<Task<T>> func)
{
var task = GetExecutableTask(func);
var result = await await task;
if (!task.IsInvalid)
{
result = default(T);
}
return (task.IsInvalid, result);
}
实践测试
启动10个并发任务,测试实际的任务队列并发操作管理:
public MainWindow()
{
InitializeComponent();
_asyncTaskQueue = new AsyncTaskQueue
{
AutoCancelPreviousTask = true,
UseSingleThread = true
};
}
private AsyncTaskQueue _asyncTaskQueue;
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
// 快速启动9个任务
for (var i = ; i < ; i++)
{
Test(_asyncTaskQueue, i);
}
}
public static async void Test(AsyncTaskQueue taskQueue, int num)
{
var result = await taskQueue.ExecuteAsync(async () =>
{
Debug.WriteLine("输入:" + num);
// 长时间耗时任务
await Task.Delay(TimeSpan.FromSeconds());
return num * ;
});
Debug.WriteLine($"{num}输出的:" + result);
}
测试结果如下:
一共9次操作,只有最后一次操作结果,才是有效的。其它8次操作,一次是无效的,7次操作被取消不执行。
C# 异步并发操作,只保留最后一次操作的更多相关文章
- GCD 之 同步 异步 并发
1. dispatch_async(dispatch_get_global_queue(, ), ^{ // 处理耗时操作的代码块... //通知主线程刷新 dispatch_async(dispat ...
- Node.js的那些坑——如何让异步并发方法同步顺序执行(for循环+异步操作)
1 前言 nodejs的回调,有时候真的是让人又爱又恨的,当需要用for循环把数据依次存入数据库,但是如果使用正常的for循环,永远都是最后一次值的记录,根本不符合要求. 解决此方案有几种,例如闭包( ...
- 异步并发利器:实际项目中使用CompletionService提升系统性能的一次实践
场景 随着互联网应用的深入,很多传统行业也都需要接入到互联网.我们公司也是这样,保险核心需要和很多保险中介对接,比如阿里.京东等等.这些公司对于接口服务的性能有些比较高的要求,传统的核心无法满足要求, ...
- 你真的会玩SQL吗?删除重复数据且只保留一条
在网上看过一些解决方法 我在此给出的方法适用于无唯一ID的情形 表:TB_MACVideoAndPicture 字段只有2个:mac,content mac作为ID,正常情况下mac数据是唯一的,由于 ...
- 【Python】迭代器、生成器、yield单线程异步并发实现详解
转自http://blog.itpub.net/29018063/viewspace-2079767 大家在学习python开发时可能经常对迭代器.生成器.yield关键字用法有所疑惑,在这篇文章将从 ...
- Python 开源异步并发框架的未来
http://segmentfault.com/a/1190000000471602 开源 Python 是开源的,介绍的这几个框架 Twisted.Tornado.Gevent 和 tulip 也都 ...
- Python开源异步并发框架
Python开源异步并发框架的未来 2014年3月30日,由全球最大的中文IT社区CSDN主办的“开源技术大会·” (Open Source Technology Conference ,简称OSTC ...
- python异步并发模块concurrent.futures入门详解
concurrent.futures是一个非常简单易用的库,主要用来实现多线程和多进程的异步并发. 本文主要对concurrent.futures库相关模块进行详解,并分别提供了详细的示例demo. ...
- SQL Server 删除重复记录,只保留一条记录
原文地址:http://blog.csdn.net/eriato/article/details/17417303 有张表格之前没有设计关键字段的唯一约束,导致有时候执行插入操作时不小心执行了多次就出 ...
随机推荐
- docker安装sshd
基础镜像: ubuntu:14.04 启动并安装sshd //启动 docker run -it ubuntu:14.04 /bin/bash //更新apt-get apt-get update / ...
- 适用于Windows桌面应用程序的.NET Core 3
介绍 9月,微软发布了新版.NET Core,用于构建Windows桌面应用程序,包括WPF和Windows Forms.从那时起开发人员可以将传统的nfx桌面应用程序(和控件库)迁移到.NET Co ...
- TICK技术栈(三)InfluxDB安装及使用
1.什么是InfluxDB? InfluxDB是一个用Go语言开发的时序数据库,用于处理高写入和查询负载,专门为带时间戳的数据编写,对DevOps监控,IoT监控和实时分析等应用场景非常有用.通过自定 ...
- 获得shell的几种姿势
windows提权 1.通过sqlmap连接mysql获取shell (1)直接连接数据库 sqlmap.py -d "mysql://root:123456@127.0.0.1:3306/ ...
- AutoCad 二次开发 .net 之相同块的自动编号
主要步骤: 一.获取一个块的id: 其中oId就是了. 二.通过次oId获取块引用blkRef: 三.通过它获取所有相同的块引用的id集合: 四.通过步骤三的集合得到所有的块引用得到集合listBr: ...
- [ZJOI2013]K大数查询——整体二分
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是: 1 a b c:表示在第a个位置到第b个位置,每个位置加上一个数c 2 a b c:表示询问从第a个位置到第b个位置,第C大的数是多少. ...
- wordpress插件:multiple post thumbnails(可为文章添加多个特色图片)
我们经常会给wordpress的文章加上特色图片来实现日志缩略图的需求,但是很多时候一张图片并不能够完美而又全面的表达我们wordpress文章的内容,这时候您可能就会需要这样一个能让wordpres ...
- 小白学 Python(20):迭代器基础
人生苦短,我选Python 前文传送门 小白学 Python(1):开篇 小白学 Python(2):基础数据类型(上) 小白学 Python(3):基础数据类型(下) 小白学 Python(4):变 ...
- 手把手带你实战下Spring的七种事务传播行为
目录 本文目录 一.什么是事务传播行为? 二.事务的7种传播行为 三.7种传播行为实战 本文介绍Spring的七种事务传播行为并通过代码演示下. 本文目录 一.什么是事务传播行为? 事务传播行为(pr ...
- python——int()、hex()、oct()、bin()、float()数值类型转换函数
摘要:在python中,数值类型转换函数常用的有浮点型float().取整int().八进制oct().二进制bin().十六进制hex()这五个函数. 单词float的意思就是浮动的意思: int是 ...