延迟合并处理任务

我们经常会遇到一种情况,在带有智能提示的文本框,在输入内容时,会实时或准实时弹出提示下拉框,里面包含系统猜测你可能要输入的内容。当这些搜索建议来自服务器的时候,有时你会觉得这种智能提示对服务器的负载有点大,毕竟但用户输入完一定内容之前,会产生多余的运算和流量,在此过程中所产生的结果甚至用户根本不会留意,因此还不如忽略掉这期间的过程。

那么,如何做到这一点呢?

延迟合并处理任务应运而生。其实,不光前面所说的这个场景,还有许多情况也会需要应用到这种类型的任务。该任务满足一下几点功能条件。

  • 可以创建一个任务方法,里面会包含注册的业务方法。任务方法用于在需要延迟调用业务方法的地方调用,后续的延迟与合并操作会由任务方法自动处理。
  • 在任务方法执行时,会在延迟一段时间后才执行所注册的业务方法。
  • 任务方法可以在不同地方分别调用多次。
  • 当上一个任务方法的延迟时限还没到时,如果下一个任务方法被调用,那么上一个任务方法会被终止,也即此时只会在最后一个任务方法中经过延迟一段时间后调用业务方法。此乃置后合并是也,用于过滤掉前面的多余执行。

为此,我们可以设计一个通用的方式,来解决这些问题。我们需要新写一个类,里面需要提供一个时长设置,即两次触发之间的最长间隔,短语该间隔的两次触发将会被自动合并;还需要一个事件,用于在触发真正被认定为需要执行时,会抛该事件,业务逻辑可以绑定在该事件上;最后,还需要一个异步方法,即用于尝试执行触发,其应当返回最终是否真实触发。

 1 public class DelayTask
 2 {
 3     public TimeSpan Span { get; set; }
 4
 5     public event EventHandler Processed;
 6
 7     public async Task<bool> Process()
 8     {
 9         throw new NotImplementedException();
10     }
11
12 }

当然,在此之前,其实我们应该先引用一些命名空间。

1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;

好了,我们继续实现该类。在 Process 成员方法中,我们计划延迟执行预期操作。然而,对于正在处理的过程中,如果有新的触发进来,则我们应当将之前触发摒弃掉。一个简单的做法是,之前触发在等待后,进行一次校验。这时,我们需要通过一个标识符来作为判断的依据。每次新的触发进来时,需要重置该标识符,并记录下来,并在等待一段时间后,用记录下来的标识符和当前最新的进行比较,如果相等,则说明没有新的触发进来,否则直接停止执行。

 1 private Guid _token = Guid.Empty;
 2
 3 public async Task<bool> Process()
 4 {
 5     var token = Guid.NewGuid();
 6     _token = token;
 7     await Task.Delay(Span);
 8     if (token != _token) return false;
 9     _token = Guid.Empty;
10     Processed(this, new EventArgs());
11     return true;
12 }

当然,也可以用 CancellationToken 来提前终止,此处就不做此优化了。但对于 Process 本身,我们将加入该取消机制。于是我们得到最终代码。

 1 /// <summary>
 2 /// The delay task.
 3 /// </summary>
 4 public class DelayTask
 5 {
 6     private Guid _token = Guid.Empty;
 7
 8     /// <summary>
 9     /// Gets or sets the delay time span.
10     /// </summary>
11     public TimeSpan Span { get; set; }
12
13     /// <summary>
14     /// Adds or removes the event handler occurred
15     /// after processed.
16     /// </summary>
17     public event EventHandler Processed;
18
19     /// <summary>
20     /// Processes the delay task.
21     /// </summary>
22     /// <returns>
23     /// A task with a value indicating whether it executes.
24     /// </returns>
25     public async Task<bool> Process()
26     {
27         return await Process(CancellationToken.None);
28     }
29
30     /// <summary>
31     /// Processes the delay task.
32     /// </summary>
33     /// <param name="cancellationToken">
34     /// The cancellation token that will be checked prior
35     /// to completing the returned task.
36     /// </param>
37     /// <returns>
38     /// A task with a value indicating whether it executes.
39     /// </returns>
40     public async Task<bool> Process(
41         CancellationToken cancellationToken)
42     {
43         var token = Guid.NewGuid();
44         _token = token;
45         await Task.Delay(Span, cancellationToken);
46         if (token != _token) return false;
47         _token = Guid.Empty;
48         if (cancellationToken.IsCancellationRequested)
49             return false;
50         Processed(this, new EventArgs());
51         return true;
52     }
53 }

这个类的使用也非常方便,只需初始化该对象,然后设置好最长间隔时长,并将原先的业务逻辑绑定到其事件上,然后在原本应当调用业务逻辑的地方,调用其 Process 方法即可。

【完】

文章类型及复杂度:C# 和 .Net 进阶。

节选翻译自 MSDN 博文 Delay Task,内容有所调整。

http://blogs.msdn.com/b/kingcean/archive/2016/03/20/delay-task.aspx

时间: 2024-10-22 21:11:55

延迟合并处理任务的相关文章

ASP.NET 缓存技术分析

缓存功能是大型网站设计一个很重要的部分.由数据库驱动的Web应用程序,如果需要改善其性能,最好的方法是使用缓存功能.可能的情况下尽量使用缓 存,从内存中返回数据的速度始终比去数据库查的速度快,因而可以大大提供应用程序的性能.毕竟现在内存非常便宜,用空间换取时间效率应该是非常划算的.尤 其是对耗时比较长的.需要建立网络链接的数据库查询操作等. 对于web页面的缓存,WebForm与ASP.NET MVC有不同的语法.在WebForm中, <%@ OutputCache Duration="6

每天4亿行SQLite订单大数据测试(源码)

SQLite单表4亿订单,大数据测试 SQLite作为嵌入式数据库的翘楚,广受欢迎!新生命团队自2010年以来,投入大量精力对SQLite进行学习研究,成功应用于各系统非致命数据场合. SQLite极致性能 关闭同步,Synchronous=Off,提升性能.添删改操作时不必同步等待写入磁盘,操作系统会延迟若干毫秒批量写入 设置WAL模式,Journal Mode=WAL,减少锁定.写入向前日志模式,避免多线程访问时锁定数据库,写入时不必使用排它锁影响其它线程读取,而是把事务操作写入到WAL文件

算法导论 第20章 斐波那契堆

一.概念 1.斐波那契堆 斐波那契堆是可合并堆 在不涉及删除的操作(除去EXTRACT和DELETE)中,操作仅需O(1)的平摊运行时间 当EXTRACT和DELETE的操作数目较小时斐波那契堆能得到较好的运行效率. 斐波那契堆不能有效地支持SEARCH操作 用于解决诸如最小生成树和寻找单源最短路径等问题的快速算法都要用到斐波那契堆. 2.斐波那契堆的结构 斐波那契堆由一组最小堆构成,这些最小堆是有根的无序树. 结点结构: key: 关键字,作为排序.判断结点大小的标准 left, right:

细说 ASP.NET Cache 及其高级用法

许多做过程序性能优化的人,或者关注过程程序性能的人,应该都使用过各类缓存技术. 而我今天所说的Cache是专指ASP.NET的Cache,我们可以使用HttpRuntime.Cache访问到的那个Cache,而不是其它的缓存技术. 以前我在[我心目中的Asp.net核心对象] 这篇博客中简单地提过它,今天我打算为它写篇专题博客,专门来谈谈它,因为它实在是太重要了.在这篇博客中, 我不仅要介绍它的一些常见用法,还将介绍它的一些高级用法. 在上篇博客[在.net中读写config文件的各种方法] 的

细说 ASP.NET Cache 及其高级用法【转】

阅读目录 开始 Cache的基本用途 Cache的定义 Cache常见用法 Cache类的特点 缓存项的过期时间 缓存项的依赖关系 - 依赖其它缓存项 缓存项的依赖关系 - 文件依赖 缓存项的移除优先级 缓存项的移除通知 巧用缓存项的移除通知 实现[延迟操作] 巧用缓存项的移除通知 实现[自动加载配置文件] 文件监视技术的选择 各种缓存方案的共存 许多做过程序性能优化的人,或者关注过程程序性能的人,应该都使用过各类缓存技术. 而我今天所说的Cache是专指ASP.NET的Cache,我们可以使用

《Thinking in Algorithm》16.堆结构之斐波那契堆

堆的变体: 二叉堆 二项堆 斐波那契堆 前面的博客中我们讲到的堆的两种变体,二叉堆和二项堆,今天我们要讲的就是著名的斐波那契堆. 依然首先列出了三种堆的时间复杂的比较. 从上面能发现斐波那契堆的时间复杂度在很多操作上有优化,如insert, minimum, union , decrease-key,而extreact-min,delete没有变化. 可能看到这很多人会说为什么有这么好的斐波那契堆,我们还要去研究其他堆呢,确实,理论上来讲,对于extreact-min和delete操作想对于其他

elasticsearch 查询优化

首先对不必要的字段不做分词也就是不做索引,禁止内存交换 1.shard 一个Shard就是一个Lucene实例,是一个完整的搜索引擎. 分片数过多会导致检索时打开比较多的文件,多台服务器之间通讯成本加大. 而分片数过少会导至单个分片索引过大,所以检索速度也会慢. 建议单个分片最多存储10G-20G左右的索引数据,并且尽量集群的所有节点都分片数一致,不要出现分片数不一样导致的一个实例负载过大,等待合并的时间变长: 2.shard副本 使用副本的优点:数据备份,提高对大索引的查询效率,建议副本在1-

sqlite3数据库最大可以是多大?可以存放多少数据?读写性能怎么样?

sqlite是款不错的数据库,使用方便,不需要事先安装软件,事先建表.很多人担心它的性能和数据存储量问题. 比如有的网友问:Sqlite数据库最大可以多大呀?会不会像acc数据库那样,几十MB就暴掉了?不会的,放心用SQLite, 这是两个数量级的东西, 看下面的说明.Access不能算真正意义上的数据库,但是Access是前台和后台在一起,对小用户还是有其优点.SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它

如何优化传输机制来实现实时音视频的超低延迟?

1.前言 要在语音视频 SDK 中实现超低延迟,实时的语音视频传输机制是必不可少的,而 FEC 和 ARQ 的智能结合是实时语音视频传输机制的基石. 在语音社交.视频社交.游戏语音和互动直播等领域,关于在语音视频实时传输中实现低延迟这个议题,已经有不少的文章提出各种方案.绝大部分方案的思路都是"优化",比如说,优化编码.推流.传输和播放等各个环节. 愚以为,要在实时语音视频传输中获得超低延迟,是不能单靠挖空心思去"优化"的,而是要依靠实时的传输机制.就像高铁和火车有