案例设计基于时间的事件响应管理器

Posted 野奔在山外的猫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了案例设计基于时间的事件响应管理器相关的知识,希望对你有一定的参考价值。

开发平台:Unity 2021
编程语言:CSharp
编程平台:Visual Studio 2022

一、前言


  程序运行的特性是 逐行关联即执行。在执行单行代码语句的效率上基于物理设备基础与底层架构逻辑。对一般程序员来看,只需要学会应用即可。但有时候,并不期望于其立即执行,甚至是不断的自我检测、等待若干时间、等待若干帧后执行。于是有了计时器的说法。本文重点记录计时器的构想与设计。

二、思考:计时器类型表现


类型描述
顺序从单位时间 0 开始计数或计次。每次值累加固定单位值。默认情况下,无上限值。即启用即不停止,直至应用程序结束。
逆序从固定时间 任意值 开始计数或计次。每次值累减固定值。默认情况下,存在下限值 0。当应用程序强制关闭或到达下限值时,停止当前逻辑。

三、思考:目前能设想的计时器实现方式(从 Unity 角度构想)


3.1 实现一:Unity 生命周期 Update/FixedUpdate

public void Updaete() 		 while(timer <= 0)  	timer -= Time.deltaTime;  
public void FixedUpdate()    while(timer <= 0)    timer -= Time.FixedTime;  

  使用 Update 更新,在一定程度上解决计时所带来的问题。但在其他方面上,Update 中计算计时选项不是明举的实现方法,于是较于 Update 有了 FixedUpdate 的更新方案。因为计时器,记录的是事件发生的时间节点。一般的,对于个人开发者而言,时间的计算精确并不需要精确至 毫秒所以 FixedUpdate 在整体刷新上并不会较 Update 次数多且耗能大。也是不错的优化方案。但最终不是最佳。

3.2 实现二:IEnumerator 协程(常用)



  协程是目前 Unity 开发者中最为常用的计时器实现方式。其特点用时则用,无用时无需调用(即 与 Update 相比,不需要持续更新,或在 Update 中添加 bool 判断环节是否执行等特点),每次使用 yield return new WaitForSecond()\\WaitForEndOfFrame() 等来延迟执行。

public IEnumerator DoTimeCount()

	yield return new WaitForSeconds(1f);
	timer += 1f;
	TimerEvent?.Invoke(timer);
	StartCoroutine(DoTimeCount());	

  • 协程特点:基于主线程上,单开一分支独立运行。不影响原主分支执行。
  • 依赖于 MonoBahaviour 实现 IEnumerator 操作(对 非 MonoBehaviour 的类对象无法调用)

四、思考:基于 IEnumerator 的计时器类封装


4.1 解决依赖问题

  IEnumerator 的启用基于 MonoBehaviour 基础上进行。非 MonoBehaviour 继承的子项无法使用 IEnumerator 进行协程操作。故其实现上应基于该对象上进行。但从以下两个角度进行思考,选择 继承 MonoBahviour 的 Mono单例 将更具备优势。

  • 单例模式下,调用方法更加直观、快速。无需实例化对象。
  • 计时器作为辅助功能,无需准备额外的 Prefab 对象用于加载时程序添加对象,或 持续存在于场景内上。从调用与项目维护上,这是不可取的行为。但在 MonoBehaviour 环境下的单例模式,建立调用时,若场景无该对象,则程序创建该对象并完成引用的行为。减少了资产中需存储特定对象的 Prefab 并管理的麻烦性。

4.2 考虑计时器的基础属性

  计时器作为统筹时间变化的重要,必要的参数包括如下:

参数数据类型说明
StartTimedecimal计时器 起始时间
EndTimedecimal计时器 终止时间
LerpTimedecimal计时器 插值时间(限制时间精度)
IsPositiveTimebool判断 计时器为 正序 or 逆序,
OnTimeEventDictionary<decimal, Action>记录 时间戳事件
  • 从精度角度考虑,float 的精确度存在较小的误差,但为了保证计时器在确切的时间。例如 0.1m,而非 0.1000002231f。使用十进制 decimal 数据类型作为标准,后续设计提供基础奠定。
  • 从程序设计角度上考虑,参数变量过多的情况,并不建议使用复数的局部变量作为配置。相比较可参考 事件 的设计思想,将变量集中于 类 中以供调用实现。

4.3 考虑计时器的拓展设计

  实际上,计时器并非仅用于计时,在应用层面上,涉及程序逻辑响应 + 时间显示。例如 0 -10s 的计时器,以单位1s作为过渡。在每个时间戳结点下,调用对应的方法与内容,以强化时间事件效果。具体如下:

  • 加入 第2s时,执行方法体 Debug.Log("Hello 2s, taking fire! Now!")
  • 加入 第2s时,执行方法体 Debug.Log("Hello 2s, Where are u from ?")
  • 加入 第4s时,执行方法体 Debug.Log("4s, R U Hungry?")
  • 加入 第9s时,执行方法体 Debug.Log("The Time will over soon")

  那么 Action 将毫无疑问的成为程序开发的首选选项。为什么?每一秒时间响应的方法内容并不局限于一种方法的内容执行。例如 在第 2s 时,添加新的方法体内容以执行。从解耦度角度考虑,新添方法体 + 原方法体 之间互不影响干涉,即两者之一的有无均不会影响 第2s 时刻的时间事件执行。则 委托、事件 是最直接可用的方法。在时间事件的注册上也更便捷快捷。

五、程序设计


5.1 关于 GameTime 的说明

public class GameTime : MonoSington<GameTime>

	public static Coroutine DoCoroutine(TimeData data)
	
		return Instance.StartCoroutine(DoPositiveTime(data));
	

	private static IEnumerator DoPositiveTime(TimeData data)
	
		yield return new WaitForSeconds(data.LerpTime);
		// 更新当前时间值
		data.CurrentTime += data.LerpTime;
		data.TimeAction[data.CurrentTime]?.Invoke();
		
		if(data.CurrentTime <= data.EndTIime)
			
			// 迭代继续
			Instance.StartCoroutine(DoPositiveTime(data));
			yield break;
		
		
		Debug.Log($"[Time Coroutinue] The Time Event Is Finish");
	

  • 从实现角度上:
    • 使用 MonoSingleton 的 Mono 单例模式实现 Mono 环境下调用 Coroutinue 的前置条件(重要)
    • 选择静态方法。直接同通过 GameTime.DoCoroutine(new Time()); 快速启用协程,降低程序上调用的复杂性。
  • 从方法命名角度上,
    • 使用 Positive / Nagetive 以区分计时器的正反顺序。
  • 更多可优化与补充内容:
    • TimeData 中注册的 TimeAction 未提供便捷的初始化方法。
      可构建 public TimeAction(decimal startTime, decimal endTime, decimal lerpTime) 用于初始化 TimeData 类。
    • 在使用习惯角度上,集成 事件注册、注销、启用、禁用 方法于 GameTime 类是最佳的选择。
      无需在 new 之后,引用新建对象中的事件注册进行。(记住多的API倒不如集合在一起,自己找)。
    • 在判断时间事件属于 顺序计时/逆序计时 上可进行数据判断,执行对应的数据内容。
      扩展 DoCoroutine ,增加判断计时器应用类型方法。
    • 考虑多类型的计时器可能同时运行,未区别其计时器具体属于何种应用的计时器,可添加 Name 属性用于 Debug 识别。

5.2 关于 TimeData 的说明

public class TimeData

	private decimal currentTime;
	
	public decimal CurrentTime  get  return currentTime; 
	public decimal StartTime    get; set; 
	public decimal EndTime      get; set; 
	public decimal LerpTime     get; set; 

	public Dictionary<decimal, Action> TimeAction  get; set; 
	
	public TimeData(decimal startTime, decimal endTime, decimal lerpTime)
	
		this.currenTime = startTime;
		this.StartTime = startTime;
        this.EndTime = endTime;
        this.LerpTime = lerpTime;
        this.OnTimeEvent = new Dictionary<decimal, Action>();
	

  • TimeData:配置事件计时器相关属性与事件的配置文件。
  • 一般情况下,一个时间触发计时器需要 开始时间、结束时间、时间插值。随着需求变化,增加展示当前数据、区别计时器类型等内容。(视实际情况而定)或许 Action 也会因为实际需求改用 Actoin<int> 或其他也说不定。

六、后记


  关于时间管理的事件管理器是作者在 BILIBILI 上偶然看见同开发者自己开发作品时萌发的设想。虽然他的视频内容我并没有太多关于他讲解时的记忆。但基于时间驱动事件这一需求设计,深深的给我留下了印象。以思考 —— 如果是我,我会怎么去实现这个需求?这篇文章也并非完整的内容。仅提供实现方式的思路参考。后续仍不定期更新完善内容。

服务案例|基于IT事件管理,提升业务连续性

数字化经济时代,IT架构复杂性越来越高,业务连续性成为很多行业或企业最核心的任务。业务连续性管理是一个不断提升的过程,围绕事件“发现-响应-定位处理-降低发生”的事件处理思路,结合平台化运维,助力业务快速提升。

我们将具体事件从监控、调查、上报和响应几个环节来处理。即当平台监控发现异常,进行事件优先级分类,判断事件处理的紧迫性,分析事件影响造成破坏程度,然后进行事故调查与诊断,快速定位识别问题,联系现场工程师最终解决问题,事件流程结束。

围绕事件提升业务连续性的优势在于:主动快速处理使业务恢复正常,将影响降至最低。流程闭环提高用户满意度,最大程度降低事件处理成本。下面我们来看案例的处理过程。

一、问题发现

夜间服务器在飞速运转,主要进行流程审批、数据库备份、报表统计这类定时、耗时的工作。夜间无人值守的机房,加上高速飞转的服务器,很容易触发故障。

2月1日凌晨4:40分,平台接到某服务器ping不通告警,检测到此服务器发生死机现象。这台服务器已经连续发生几次夜间死机故障。

二、问题分析定位

根据时序图,协助服务器管理工程师查找故障发生的具体原因。查看4:40分前后,CPU,内存和虚拟内存,磁盘使用等运维参数如下

1 CPU没有异常,空闲率达到70%以上

服务案例|基于IT事件管理,提升业务连续性_死机

2、可用内存22.28G,充足

服务案例|基于IT事件管理,提升业务连续性_运维_02

3、虚拟内存使用率只有0.49%

服务案例|基于IT事件管理,提升业务连续性_运维_03

4、硬盘剩余可用空间充足、

服务案例|基于IT事件管理,提升业务连续性_服务器_04

5、网络输出输入数据也是正常

服务案例|基于IT事件管理,提升业务连续性_死机_05

6、在4:40-6:48左右,ping不通,服务器已发生死机。4:40-6:48之间的服务器运行指标参数没有上传

服务案例|基于IT事件管理,提升业务连续性_死机_06

服务案例|基于IT事件管理,提升业务连续性_运维_07

7、从服务器发生死机前和重启后的运维参数看,服务器的资源配置充足,并非是资源争用导致死机。

8、查看服务器运行日志,服务器并没有自动进行打补丁更新,但是组策略配置有告警生成

服务案例|基于IT事件管理,提升业务连续性_死机_08

平台未接到安全攻击告警,也未接收到硬件故障告警,首先排除病毒攻击;硬件故障,服务器资源匮乏,且近期应用软件未升级、变更,其次则排除软件问题。最后锁定操作系统问题。服务器管理工程师对操作系统进行了打补丁升级处理。后期持续对这台服务器进行重点监控,未产生故障,问题得到解决。

服务器宕机,可能导致客户无法访问,业务中断造成巨大的经济损失;也可能影响数据备份,导致数据丢失;夜间无人值守,故障重启等问题不易察觉,LinkSLA智能运维管家不仅能够及时监测到服务器故障,第一时间进行反馈,可以根据历史运维指标数据,进行分析,协助用户查找出故障的根本原因,从根本上解决问题。

四、总结

除了实时发现告警,及时处理,流程闭环外,还需加强问题管理以及自动巡检服务出发,从源头上降低故障事件发生。

基于业务系统的多样性,还可为业务发展提供依据,通过一段时间的监控数据累积,利用监控系统提供的报表功能对数据进行统计处理,帮助用户做系统升级决策,如是否需要采购新硬件、是否需要新增系统节点等。另外,还可以利用系统的监控大屏功能,对系统的整体健康状况做到一目了然,做到资源、业务的可视化。

以上是关于案例设计基于时间的事件响应管理器的主要内容,如果未能解决你的问题,请参考以下文章

基于树结构实现的Unity红点管理器

FPGA教程案例9基于vivado核的时钟管理器设计与实现

Java语言程序设计 上机实验6 掌握Java的图形用户界面编程,掌握布局管理器和事件的响应方法

在 Unity 中使用委托和事件创建事件管理器(消息系统)

Unity资源管理系统 ——YooAsset学习笔记事件管理器EventManager

Unity C# 游戏开发 事件 消息派发器(图文详细,带源码)