Orleans 提供了 Timers 和 Reminders两种机制。

Timers

计时器与 .NET 里提供的 System.Threading.Timer 类基本相同。此外,计时器在单独的线程上执行。如果有多个与之关联的计时器,在运行时会进行上下文切换去执行每个计时器。

用法:

要启动计时器,直接使用 RegisterTimer 方法就可以,该方法在 Grain 类中实现,方法参数说明:

Func<object, Task> asyncCallback // 计时器开始计时调用的函数
object state                     // asyncCallback 函数所需参数
TimeSpan dueTime                 // 启动到第一次执行间隔的时间量
TimeSpan period                  // 等行为下一次执行间隔的时间量

方法返回一个 IDisposable 句柄,通过 Dispose 方法来停止计时器。

另外,一旦 Grain 被停用或者 Silo 崩坏,计时器将停止触发。

接下来我们看下使用的代码:

public interface ITimerGrain : IGrainWithIntegerKey
{Task Start();Task Finish();
}
public class TimerGrain : Grain, ITimerGrain
{private readonly ILogger logger;private IDisposable? disposable;public TimerGrain(ILogger<HelloGrain> logger){this.logger = logger;}public Task Start(){disposable = RegisterTimer(o =>{logger.LogInformation($"time tick = {DateTime.Now}\n ");return Task.CompletedTask;}, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5));return Task.CompletedTask;}public Task Finish(){if (disposable != null){logger.LogInformation($"计时器停止--{DateTime.Now}\n");disposable.Dispose();disposable = null;}return Task.CompletedTask;}
}

client 调用

var timerGrain = client.GetGrain<ITimerGrain>(1);
await timerGrain.Start();//休息个10秒钟再来取消计时器
Thread.Sleep(10000);await timerGrain.Finish();

计时器的用法比较简单,但我们也要注意如下事项:

  • 启用收集 Grain 时,计时器不会将 Grain 激活的状态从空闲更改为使用中。不会因计时器在执行回调函数而推迟取消激活原本空闲的 Grain 。Grain 一旦被停用,那么定时器也将被丢弃。

  • 从 asyncCallback 返回的 Task 被解析之前,不会执行下一次 asyncCallback 。 计时器永远不会重叠调用 asyncCallback。而且 asyncCallback 所需要的执行时间会影响到调用 asyncCallback 的频率。这与 System.Threading.Timer 一个很重要的不同点。

  • 任何由 asyncCallback 返回的异常或错误的 Task 都会被记录,但不会阻止下一次 asyncCallback 进入队列。

  • asyncCallback 调用不会作为消息传递,因此它不会受消息交互场景的影响。

以上就是 Timers 的用法。接下来看下 Reminders 。

Reminders

Reminders 翻译过来为提醒,但我觉得这不太贴切,所以就保留英文。Reminders 与计时器有类似的地方,我们先看它的用法,最后再来说它们之间的区别。

Reminders 要依赖存储,所以在使用之前要指定存储方式。存储方式可以在 Silo 配置,创建 SiloHostBuilder 对象时调用 UseXReminderService 扩展方法进行配置,其中 X 是存储方式名称。例如:我使用 MySql 数据库,在配置之前先添加 NuGet 引用 Microsoft.Orleans.Reminders.AdoNet 和 MySql.Data ,具体的配置如下:

.UseAdoNetReminderService(options => {options.ConnectionString = "Server=localhost;Port=3306;Database=yld;Uid=root;Pwd=mysql;";options.Invariant = "MySql.Data.MySqlClient";})

除了 SQL 数据库,还支持如下图:

每个具体的配置方案这里就不介绍,相信都会。另外,Orleans 还提供了一个开发环境下使用的内存存储方式,其配置比较简单直接使用 UseInMemoryReminderService 方法即可。

这里我就使用 MySql 来做示例。

先做些准备工作,创建一个数据,这里数据库名称就叫 yld 。然后到 Github 上下载 MySQL-Reminders.sql 的数据库脚本 。执行脚本,准备工作完成。 接下来按下面步骤启动一个 Reminders 。

1、定义一个 IReminderGrain 接口如下:

public interface IReminderGrain : IGrainWithIntegerKey
{Task Execute();Task Cancel();
}

2、定义一个 ReminderGrain 类,该类继承 Grain 和 IReminderGrain 、IRemindable 接口。

3、实现 IRemindable 接口里的 ReceiveReminder 方法。

4、在 Execute 方法调用 Grain 类的 RegisterOrUpdateReminder 方法,进行注册。该方法参数说明如下:

string reminderName     // 设置名称,该名称必须唯一
TimeSpan dueTime        // 启动到第一次执行间隔的时间量
TimeSpan period         // 等行为下一次执行间隔的时间量

该方法返回一个 IGrainReminder 。

5、通过 Grain 类的 UnregisterReminder 方法可以取消 Reminders ,该方法接收一个 IGrainReminder 参数。IGrainReminder 可以通过 Grain 类的 GetReminder 方法获取,GetReminder 方法是通过名称来获取 IGrainReminder 。

完整代码如下:

public class ReminderGrain : Grain, IReminderGrain, IRemindable
{private IGrainReminder? reminder;private readonly ILogger logger;public ReminderGrain(ILogger<HelloGrain> logger){this.logger = logger;}public Task Cancel(){if (reminder != null){logger.LogInformation($"结束 Reminider --{DateTime.Now}\n");UnregisterReminder(reminder);}return Task.CompletedTask;}public async Task Execute(){reminder = await RegisterOrUpdateReminder("Reminder Demo", TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(60));}public Task ReceiveReminder(string reminderName, TickStatus status){logger.LogInformation($"执行 Reminider --{DateTime.Now}\n");return Task.CompletedTask;}
}

client 调用

var reminderGrain = client.GetGrain<IReminderGrain>(1);
await reminderGrain.Execute();Console.WriteLine("待待 120 秒 ...");
Thread.Sleep(120000);Console.WriteLine("Reminder 停止--" + DateTime.Now);
await reminderGrain.Cancel();

Reminders 启动时会在数据库表 orleansreminderstable 中新增一条记录。暂停 Reminder 时会把该条记录删除。

完整代码,放在 github 上。

Timers 与 Reminders 区别

  • Reminders 是持久的,因为它通过存储,保证在部分或全部集群重启时可以继承触发,除非明确取消

  • Reminders 不会特定的时间去执行特定的任务,这样会错过时间执行任务,只能执行下一次任务。

  • Reminders 与 Grain 是相互关联,无需单独激活。

  • 如果 Reminders 还在执行中,而没有 Grain 可以关联,则会自动创建一个 Grain 。如果 Grain 状态变为空闲且被停用,则将会在下一次执行时激活该 Grain。

  • Reminders 可以通过消息传递,并受制于其它 grain 方法的交互场景。

  • Reminders 不是一个高频计时器,最小单位为 1 分钟。它的周期以分钟,小时或天为单位。不能以秒为单位会报错。

如何选择

  • grain 停用或 silo 崩掉,计时器会停止作业从而影响任务的执行,而 Reminders 不会。如果对任务执行比较重要,要求比较高,集群重启不影响任务执行,那就选 Reminders 。否则,就选择 Timers 。

  • 计时器的作业频率快,以秒或分钟为单元。而 Reminders 执行一些频率比较慢的任务,例如:以分钟、小时或天为单位。

  • 计时器可以在调用 grain 方法启动或在 Grain 类的 OnActivateAsync 方法启动。

Timers 和 Reminders 的 dueTime 参数尽量不设置为 0 。

最后,祝大家学习愉快!

Grain Timers and Reminders相关推荐

  1. Orleans 高级特性-目录

    Orleans 高级特性-目录 这里将介绍一些Orleans的高级特性,适合对Orleans已经有不少了解的用户,先列出一个索引,博客文章慢慢补充 1.使用Immutable 优化复制 2.自定义序列 ...

  2. Microsoft Orleans 之 入门指南

    Microsoft Orleans 在.net用简单方法构建高并发.分布式的大型应用程序框架. 原文:http://dotnet.github.io/orleans/ 在线文档:http://dotn ...

  3. Orleans 介绍

    前面根据 Orleans 框架创建了一个基础示例,今天结合 Orleans 文档做一个整体介绍. Actor Model 在开始之前,我们简单介绍下 Actor Model 概念,Actor Mode ...

  4. 面向.NET开发人员的Dapr- actors 构建块

    原文地址:https://docs.microsoft.com/en-us/dotnet/architecture/dapr-for-net-developers/actors The actor m ...

  5. A Grain of Sand 一粒沙子

              William Blake/威廉.布莱克 To see a world in a grain of sand, And a heaven in a wild fllower, Ho ...

  6. System.Timers.Timer的Enable、Start、Stop记录

    Timer的初始化,此时不执行theout3方法 System.Timers.Timer time = new System.Timers.Timer(); time.Interval = 1000; ...

  7. 英文谚语:Take that with a grain of salt

    take sth. with a grain of salt 这个习语的字面意思是"和一撮盐一起吃下去",为什么要与盐一起吃呢? 据说这个习语要追溯到罗马时代,罗马将军庞培曾发现一 ...

  8. C# System.Timers.Timer中的坑,程序异常退出后timer依然运行问题

    C# System.Timers.Timer中的坑,程序异常退出后timer依然运行问题 参考文章: (1)C# System.Timers.Timer中的坑,程序异常退出后timer依然运行问题 ( ...

  9. System.Timers.Timer与System.Threading.Timer

    我最近一直在查看一些可能的计时器,而Threading.Timer和Timers.Timer对我来说是必要的(因为它们支持线程池). 我正在制作游戏,我计划使用不同类型的活动,间隔不同等. 哪个最好? ...

  10. Timers cannot be stopped from another thread

    Timers cannot be stopped from another thread 我发现的一种情况: 线程异常退出了,并不是线程本身有问题,是线程里面报错了.

最新文章

  1. composer爆错:zlib_decode():data error
  2. 图形处理相关资源(面部识别、姿态估计、变形、、、)
  3. 开发时间及内容(二)
  4. Distributed Systems笔记-Cryptographic Protocols
  5. Nature论文解读:用于改善加权生物网络信噪比的网络增强方法
  6. android aar编程,AndroidStudio脚本命令指定AAR生成目录与版本号
  7. python电脑版软件下载_Python for windows
  8. [转]SQL语句资料
  9. 动手学深度学习(PyTorch实现)(十二)--批量归一化(BatchNormalization)
  10. 十八般武艺玩转GaussDB(DWS)性能调优:SQL改写
  11. [转]Fedora Core Linux 9 中安装VMware Tools-6.5.0
  12. 今天开始学习ADO.NET中的Connection对象(一)--SqlConnection对象连接SQL Server
  13. 设置div背景颜色透明度,内部元素不透明
  14. 计算机毕业设计ssm基于远程协作的汽车故障诊断系统t6ipg系统+程序+源码+lw+远程部署
  15. C语言:L1-009 N个数求和 (20 分)
  16. 一个简单的学籍信息管理系统,基于PHP和Bootstrap的实现
  17. vue3 ref 和reactive的区别
  18. 2018年互联网生死场,京东网易ofo知乎等公司裁员,没有一丝防备
  19. Frog Jumps
  20. 辽宁省中职高考计算机专业,2017年辽宁民族师范高等专科学校单招(计算机)考试大纲(中职生)...

热门文章

  1. onclick和onfocus的区别
  2. 找出直系亲属-cpp
  3. D. Bouncing Boomerangs
  4. Java 图片转换base64
  5. RAP简介教程常用规则
  6. 智能abc是什么输入法:win10可用的智能abc输入法免费下载
  7. 5个最佳开源环境电子邮件客户端
  8. 浩辰cad2017破解版|浩辰电气cad2017无限使用破解版下载
  9. 抖音APP终极瘦身方案
  10. HTML多画面同时播放,视频两个画面同时播放,两个视频放在同一画面|视频左右或上下两个画面...