服务器的话就没有Update了 所以我们要吧计时器从Mono和他自带的计时方法剥离出来
管理类只做一些简单的调用 启动Update
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
///
/// 支持时间定时,帧定时
/// 定时任务可循环 取消 替换
///
public class TimerSys : MonoBehaviour
{
//单例
public static TimerSys Instance;
PETimer pt = new PETimer();
public void Init()
{
Instance = this;
pt.SetLog((string info)=> {
Debug.Log("PETimerLog" + info);
});
}
private void Update()
{
pt.Update();
}
///
/// 添加一个计时器
///
///
///
///
///
///
public int AddTimeTask(Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)
{
return pt.AddTimeTask(callBack, delay, count, timeUnit);
}
///
/// 移除一个计时器
///
///
///
public bool DeleteTimeTask(int tid)
{
return pt.DeleteTimeTask(tid);
}
///
/// 替换
///
///
///
///
///
///
///
public bool ReplaceTimeTask(int tid, Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)
{
return pt.ReplaceTimeTask(tid, callBack, delay, count, timeUnit);
}
///
/// 添加一个帧计时器
///
///
///
///
///
///
public int AddFrameTask(Action callBack, int delay, int count = 1)
{
return pt.AddFrameTask(callBack, delay, count);
}
///
/// 移除一个帧计时器
///
///
///
public bool DeleteFrameTask(int tid)
{
return pt.DeleteFrameTask(tid);
}
///
/// 替换帧计时器
///
///
///
///
///
///
///
public bool ReplaceFrameTask(int tid, Action callBack, int delay, int count = 1)
{
return pt.ReplaceFrameTask(tid, callBack, delay, count);
}
}
把其他逻辑放到另外的类里面
using System.Collections.Generic;
using System;
public class PETimeTask
{
public int tid;
public double destTime;//单位:毫秒
public Action callBack;
public double delay;
public int count;//次数
public PETimeTask(int tid, double destTime, Action callBack, double delay, int count)
{
this.tid = tid;
this.destTime = destTime;
this.callBack = callBack;
this.count = count;
this.delay = delay;
}
}
public class PEFrameTask
{
public int tid;
public int destFrame;//单位:毫秒
public Action callBack;
public int delay;
public int count;//次数
public PEFrameTask(int tid, int destFrame, Action callBack, int delay, int count)
{
this.tid = tid;
this.destFrame = destFrame;
this.callBack = callBack;
this.count = count;
this.delay = delay;
}
}
public enum EPETimeUnit
{
Millisecond = 0,
Second,
Minute,
Hour,
Day
}
///
/// 支持时间定时,帧定时
/// 定时任务可循环 取消 替换
///
public class PETimer
{
Action taskLog;
//声明锁
static readonly string obj = "lock";
//C#的计时 计算机元年
DateTime startDateTime = new DateTime(1970,1,1,0,0,0);
double nowTime;
int tid;
List tids = new List();
///
/// tid缓存回收
///
List recTids = new List();
///
/// 临时列表 支持多线程操作 错开时间操作 避免使用锁 提升操作效率
///
List tmpTimes = new List();
List taskTimes = new List();
int frameCounter;
List tmpFrames = new List();
List taskFrames = new List();
public PETimer()
{
tids.Clear();
recTids.Clear();
tmpTimes.Clear();
taskTimes.Clear();
tmpFrames.Clear();
taskFrames.Clear();
}
public void Update()
{
CheckTimeTask();
CheckFrameTask();
if (recTids.Count > 0)
{
RecycleTid();
}
}
void CheckTimeTask()
{
//加入缓存区中的定时任务
for (int i = 0; i < tmpTimes.Count; i++)
{
taskTimes.Add(tmpTimes[i]);
}
tmpTimes.Clear();
nowTime = GetUTCMilliseconds();
//遍历检测任务是否到达条件
for (int i = 0; i < taskTimes.Count; i++)
{
PETimeTask task = taskTimes[i];
//nowTime>task.destTime 1 nowTime
if (nowTime.CompareTo(task.destTime)<0)
{
continue;
}
else
{
try
{
//时间到 callBack不为空调用
task.callBack?.Invoke();
}
catch (Exception e)
{
LogInfo(e.ToString());
}
if (task.count == 1)
{
taskTimes.RemoveAt(i);
i--;
recTids.Add(task.tid);
}
else
{
if (task.count != 0)
{
task.count -= 1;
}
//重新赋值时间
task.destTime += task.delay;
}
}
}
}
void CheckFrameTask()
{
//加入缓存区中的定时任务
for (int i = 0; i < tmpFrames.Count; i++)
{
taskFrames.Add(tmpFrames[i]);
}
tmpFrames.Clear();
frameCounter += 1;
//遍历检测任务是否到达条件
for (int i = 0; i < taskFrames.Count; i++)
{
PEFrameTask task = taskFrames[i];
if (frameCounter < task.destFrame)
{
continue;
}
else
{
try
{
//时间到 callBack不为空调用
task.callBack?.Invoke();
}
catch (Exception e)
{
LogInfo(e.ToString());
}
if (task.count == 1)
{
taskFrames.RemoveAt(i);
i--;
recTids.Add(task.tid);
}
else
{
if (task.count != 0)
{
task.count -= 1;
}
//重新赋值时间
task.destFrame += task.delay;
}
}
}
}
#region TimeTask
///
/// 添加一个计时器
///
///
///
///
///
///
public int AddTimeTask(Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)
{
//时间单位换算 最小毫秒
if (timeUnit != EPETimeUnit.Millisecond)
{
switch (timeUnit)
{
case EPETimeUnit.Second:
delay = delay * 1000;
break;
case EPETimeUnit.Minute:
delay = delay * 1000 * 60;
break;
case EPETimeUnit.Hour:
delay = delay * 1000 * 60 * 60;
break;
case EPETimeUnit.Day:
delay = delay * 1000 * 60 * 60 * 24;
break;
default:
LogInfo("Add Task TimeUnit Type error");
break;
}
}
int tid = GetTid();
//从游戏开始到现在的时间
nowTime = GetUTCMilliseconds();
tmpTimes.Add(new PETimeTask(tid, nowTime+delay, callBack, delay, count));
tids.Add(tid);
return tid;
}
///
/// 移除一个计时器
///
///
///
public bool DeleteTimeTask(int tid)
{
bool exist = false;
for (int i = 0; i < taskTimes.Count; i++)
{
PETimeTask task = taskTimes[i];
if (task.tid == tid)
{
taskTimes.RemoveAt(i);
for (int j = 0; j < tids.Count; j++)
{
if (tids[j] == tid)
{
tids.RemoveAt(j);
break;
}
}
exist = true;
break;
}
}
if (!exist)
{
for (int i = 0; i < tmpTimes.Count; i++)
{
PETimeTask task = tmpTimes[i];
if (task.tid == tid)
{
tmpTimes.RemoveAt(i);
for (int j = 0; j < tids.Count; j++)
{
if (tids[j] == tid)
{
tids.RemoveAt(j);
break;
}
}
exist = true;
break;
}
}
}
return exist;
}
///
/// 替换
///
///
///
///
///
///
///
public bool ReplaceTimeTask(int tid, Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)
{
//时间单位换算 最小毫秒
if (timeUnit != EPETimeUnit.Millisecond)
{
switch (timeUnit)
{
case EPETimeUnit.Second:
delay = delay * 1000;
break;
case EPETimeUnit.Minute:
delay = delay * 1000 * 60;
break;
case EPETimeUnit.Hour:
delay = delay * 1000 * 60 * 60;
break;
case EPETimeUnit.Day:
delay = delay * 1000 * 60 * 60 * 24;
break;
default:
LogInfo("Add Task TimeUnit Type error");
break;
}
}
//从游戏开始到现在的时间
nowTime = GetUTCMilliseconds();
PETimeTask newTask = new PETimeTask(tid, nowTime+delay, callBack, delay, count);
bool isRep = false;
for (int i = 0; i < taskTimes.Count; i++)
{
if (taskTimes[i].tid == tid)
{
taskTimes[i] = newTask;
isRep = true;
break;
}
}
if (!isRep)
{
for (int i = 0; i < tmpTimes.Count; i++)
{
if (tmpTimes[i].tid == tid)
{
tmpTimes[i] = newTask;
isRep = true;
break;
}
}
}
return isRep;
}
#endregion
#region FrameTask
///
/// 添加一个帧计时器
///
///
///
///
///
///
public int AddFrameTask(Action callBack, int delay, int count = 1)
{
int tid = GetTid();
taskFrames.Add(new PEFrameTask(tid, frameCounter + delay, callBack, delay, count));
tids.Add(tid);
return tid;
}
///
/// 移除一个帧计时器
///
///
///
public bool DeleteFrameTask(int tid)
{
bool exist = false;
for (int i = 0; i < taskFrames.Count; i++)
{
PEFrameTask task = taskFrames[i];
if (task.tid == tid)
{
taskFrames.RemoveAt(i);
for (int j = 0; j < tids.Count; j++)
{
if (tids[j] == tid)
{
tids.RemoveAt(j);
break;
}
}
exist = true;
break;
}
}
if (!exist)
{
for (int i = 0; i < tmpFrames.Count; i++)
{
PEFrameTask task = tmpFrames[i];
if (task.tid == tid)
{
tmpFrames.RemoveAt(i);
for (int j = 0; j < tids.Count; j++)
{
if (tids[j] == tid)
{
tids.RemoveAt(j);
break;
}
}
exist = true;
break;
}
}
}
return exist;
}
///
/// 替换帧计时器
///
///
///
///
///
///
///
public bool ReplaceFrameTask(int tid, Action callBack, int delay, int count = 1)
{
PEFrameTask newTask = new PEFrameTask(tid, frameCounter + delay, callBack, delay, count);
bool isRep = false;
for (int i = 0; i < taskFrames.Count; i++)
{
if (taskFrames[i].tid == tid)
{
taskFrames[i] = newTask;
isRep = true;
break;
}
}
if (!isRep)
{
for (int i = 0; i < tmpFrames.Count; i++)
{
if (tmpFrames[i].tid == tid)
{
tmpFrames[i] = newTask;
isRep = true;
break;
}
}
}
return isRep;
}
#endregion
public void SetLog(Action log)
{
taskLog = log;
}
#region Tool Methonds
int GetTid()
{
lock (obj)
{
tid += 1;
//安全代码,以防万一(服务器)
while (true)
{
if (tid == int.MaxValue)
{
tid = 0;
}
//最后一个归0后从新赋值唯一id
bool used = false;
for (int i = 0; i < tids.Count; i++)
{
if (tid == tids[i])
{
used = true;
break;
}
}
if (!used)
{
break;
}
else
{
tid += 1;
}
}
}
return tid;
}
///
/// tid回收
///
void RecycleTid()
{
for (int i = 0; i < recTids.Count; i++)
{
int tid = recTids[i];
for (int j = 0; j < tids.Count; j++)
{
if (tids[j] == tid)
{
tids.RemoveAt(j);
break;
}
}
}
recTids.Clear();
}
void LogInfo(string info)
{
taskLog?.Invoke(info);
}
///
/// 获取时间的方法
///
///
double GetUTCMilliseconds()
{
//Now是本机时间
//现在世界标准时间-计算机元年时间
TimeSpan ts = DateTime.UtcNow - startDateTime;
//返回TimeSpan值表示的毫秒数
return ts.TotalMilliseconds;
}
#endregion
}
调用类不用改变
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
///
/// 支持时间定时,帧定时
/// 定时任务可循环 取消 替换
///
public class TimerSys : MonoBehaviour
{
//单例
public static TimerSys Instance;
PETimer pt = new PETimer();
public void Init()
{
Instance = this;
pt.SetLog((string info)=> {
Debug.Log("PETimerLog" + info);
});
}
private void Update()
{
pt.Update();
}
///
/// 添加一个计时器
///
///
///
///
///
///
public int AddTimeTask(Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)
{
return pt.AddTimeTask(callBack, delay, count, timeUnit);
}
///
/// 移除一个计时器
///
///
///
public bool DeleteTimeTask(int tid)
{
return pt.DeleteTimeTask(tid);
}
///
/// 替换
///
///
///
///
///
///
///
public bool ReplaceTimeTask(int tid, Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)
{
return pt.ReplaceTimeTask(tid, callBack, delay, count, timeUnit);
}
///
/// 添加一个帧计时器
///
///
///
///
///
///
public int AddFrameTask(Action callBack, int delay, int count = 1)
{
return pt.AddFrameTask(callBack, delay, count);
}
///
/// 移除一个帧计时器
///
///
///
public bool DeleteFrameTask(int tid)
{
return pt.DeleteFrameTask(tid);
}
///
/// 替换帧计时器
///
///
///
///
///
///
///
public bool ReplaceFrameTask(int tid, Action callBack, int delay, int count = 1)
{
return pt.ReplaceFrameTask(tid, callBack, delay, count);
}
}
image.png
都没问题 打开VS新建控制台程序
image.png
image.png
image.png
找到路径把之前PETimer代码粘贴过来 这样
image.png
进入VS
image.png
选中这俩包括在项目中
image.png
然后在Program里main函数写调用
然后服务器用计时器定时数量庞大 把计算量分离出来
using System.Collections.Generic;
using System;
using System.Timers;
public class PETimeTask
{
public int tid;
public double destTime;//单位:毫秒
public Action callBack;
public double delay;
public int count;//次数
public PETimeTask(int tid, double destTime, Action callBack, double delay, int count)
{
this.tid = tid;
this.destTime = destTime;
this.callBack = callBack;
this.count = count;
this.delay = delay;
}
}
public class PEFrameTask
{
public int tid;
public int destFrame;//单位:毫秒
public Action callBack;
public int delay;
public int count;//次数
public PEFrameTask(int tid, int destFrame, Action callBack, int delay, int count)
{
this.tid = tid;
this.destFrame = destFrame;
this.callBack = callBack;
this.count = count;
this.delay = delay;
}
}
public enum EPETimeUnit
{
Millisecond = 0,
Second,
Minute,
Hour,
Day
}
///
/// 支持时间定时,帧定时
/// 定时任务可循环 取消 替换
///
public class PETimer
{
Action taskLog;
//声明锁
static readonly string obj = "lock";
//C#的计时 计算机元年
DateTime startDateTime = new DateTime(1970,1,1,0,0,0,0);
double nowTime;
Timer srvTimer;
int tid;
List tids = new List();
///
/// tid缓存回收
///
List recTids = new List();
///
/// 临时列表 支持多线程操作 错开时间操作 避免使用锁 提升操作效率
///
List tmpTimes = new List();
List taskTimes = new List();
int frameCounter;
List tmpFrames = new List();
List taskFrames = new List();
///
///
///
/// 调用运行间隔服务器用
public PETimer(int interval=0)
{
tids.Clear();
recTids.Clear();
tmpTimes.Clear();
taskTimes.Clear();
tmpFrames.Clear();
taskFrames.Clear();
if (interval!=0)
{
srvTimer = new Timer(interval) {
AutoReset = true //设置是否循环
};
srvTimer.Elapsed += (object sender, ElapsedEventArgs arg) => {
Update();
};
srvTimer.Start();
}
}
public void Update()
{
CheckTimeTask();
CheckFrameTask();
if (recTids.Count > 0)
{
RecycleTid();
}
}
void CheckTimeTask()
{
//加入缓存区中的定时任务
for (int i = 0; i < tmpTimes.Count; i++)
{
taskTimes.Add(tmpTimes[i]);
}
tmpTimes.Clear();
nowTime = GetUTCMilliseconds();
//遍历检测任务是否到达条件
for (int i = 0; i < taskTimes.Count; i++)
{
PETimeTask task = taskTimes[i];
//nowTime>task.destTime 1 nowTime
if (nowTime.CompareTo(task.destTime)<0)
{
continue;
}
else
{
try
{
//时间到 callBack不为空调用
task.callBack?.Invoke();
}
catch (Exception e)
{
LogInfo(e.ToString());
}
if (task.count == 1)
{
taskTimes.RemoveAt(i);
i--;
recTids.Add(task.tid);
}
else
{
if (task.count != 0)
{
task.count -= 1;
}
//重新赋值时间
task.destTime += task.delay;
}
}
}
}
void CheckFrameTask()
{
//加入缓存区中的定时任务
for (int i = 0; i < tmpFrames.Count; i++)
{
taskFrames.Add(tmpFrames[i]);
}
tmpFrames.Clear();
frameCounter += 1;
//遍历检测任务是否到达条件
for (int i = 0; i < taskFrames.Count; i++)
{
PEFrameTask task = taskFrames[i];
if (frameCounter < task.destFrame)
{
continue;
}
else
{
try
{
//时间到 callBack不为空调用
task.callBack?.Invoke();
}
catch (Exception e)
{
LogInfo(e.ToString());
}
if (task.count == 1)
{
taskFrames.RemoveAt(i);
i--;
recTids.Add(task.tid);
}
else
{
if (task.count != 0)
{
task.count -= 1;
}
//重新赋值时间
task.destFrame += task.delay;
}
}
}
}
#region TimeTask
///
/// 添加一个计时器
///
///
///
///
///
///
public int AddTimeTask(Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)
{
//时间单位换算 最小毫秒
if (timeUnit != EPETimeUnit.Millisecond)
{
switch (timeUnit)
{
case EPETimeUnit.Second:
delay = delay * 1000;
break;
case EPETimeUnit.Minute:
delay = delay * 1000 * 60;
break;
case EPETimeUnit.Hour:
delay = delay * 1000 * 60 * 60;
break;
case EPETimeUnit.Day:
delay = delay * 1000 * 60 * 60 * 24;
break;
default:
LogInfo("Add Task TimeUnit Type error");
break;
}
}
int tid = GetTid();
//从游戏开始到现在的时间
nowTime = GetUTCMilliseconds();
tmpTimes.Add(new PETimeTask(tid, nowTime+delay, callBack, delay, count));
tids.Add(tid);
return tid;
}
///
/// 移除一个计时器
///
///
///
public bool DeleteTimeTask(int tid)
{
bool exist = false;
for (int i = 0; i < taskTimes.Count; i++)
{
PETimeTask task = taskTimes[i];
if (task.tid == tid)
{
taskTimes.RemoveAt(i);
for (int j = 0; j < tids.Count; j++)
{
if (tids[j] == tid)
{
tids.RemoveAt(j);
break;
}
}
exist = true;
break;
}
}
if (!exist)
{
for (int i = 0; i < tmpTimes.Count; i++)
{
PETimeTask task = tmpTimes[i];
if (task.tid == tid)
{
tmpTimes.RemoveAt(i);
for (int j = 0; j < tids.Count; j++)
{
if (tids[j] == tid)
{
tids.RemoveAt(j);
break;
}
}
exist = true;
break;
}
}
}
return exist;
}
///
/// 替换
///
///
///
///
///
///
///
public bool ReplaceTimeTask(int tid, Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)
{
//时间单位换算 最小毫秒
if (timeUnit != EPETimeUnit.Millisecond)
{
switch (timeUnit)
{
case EPETimeUnit.Second:
delay = delay * 1000;
break;
case EPETimeUnit.Minute:
delay = delay * 1000 * 60;
break;
case EPETimeUnit.Hour:
delay = delay * 1000 * 60 * 60;
break;
case EPETimeUnit.Day:
delay = delay * 1000 * 60 * 60 * 24;
break;
default:
LogInfo("Add Task TimeUnit Type error");
break;
}
}
//从游戏开始到现在的时间
nowTime = GetUTCMilliseconds();
PETimeTask newTask = new PETimeTask(tid, nowTime+delay, callBack, delay, count);
bool isRep = false;
for (int i = 0; i < taskTimes.Count; i++)
{
if (taskTimes[i].tid == tid)
{
taskTimes[i] = newTask;
isRep = true;
break;
}
}
if (!isRep)
{
for (int i = 0; i < tmpTimes.Count; i++)
{
if (tmpTimes[i].tid == tid)
{
tmpTimes[i] = newTask;
isRep = true;
break;
}
}
}
return isRep;
}
#endregion
#region FrameTask
///
/// 添加一个帧计时器
///
///
///
///
///
///
public int AddFrameTask(Action callBack, int delay, int count = 1)
{
int tid = GetTid();
taskFrames.Add(new PEFrameTask(tid, frameCounter + delay, callBack, delay, count));
tids.Add(tid);
return tid;
}
///
/// 移除一个帧计时器
///
///
///
public bool DeleteFrameTask(int tid)
{
bool exist = false;
for (int i = 0; i < taskFrames.Count; i++)
{
PEFrameTask task = taskFrames[i];
if (task.tid == tid)
{
taskFrames.RemoveAt(i);
for (int j = 0; j < tids.Count; j++)
{
if (tids[j] == tid)
{
tids.RemoveAt(j);
break;
}
}
exist = true;
break;
}
}
if (!exist)
{
for (int i = 0; i < tmpFrames.Count; i++)
{
PEFrameTask task = tmpFrames[i];
if (task.tid == tid)
{
tmpFrames.RemoveAt(i);
for (int j = 0; j < tids.Count; j++)
{
if (tids[j] == tid)
{
tids.RemoveAt(j);
break;
}
}
exist = true;
break;
}
}
}
return exist;
}
///
/// 替换帧计时器
///
///
///
///
///
///
///
public bool ReplaceFrameTask(int tid, Action callBack, int delay, int count = 1)
{
PEFrameTask newTask = new PEFrameTask(tid, frameCounter + delay, callBack, delay, count);
bool isRep = false;
for (int i = 0; i < taskFrames.Count; i++)
{
if (taskFrames[i].tid == tid)
{
taskFrames[i] = newTask;
isRep = true;
break;
}
}
if (!isRep)
{
for (int i = 0; i < tmpFrames.Count; i++)
{
if (tmpFrames[i].tid == tid)
{
tmpFrames[i] = newTask;
isRep = true;
break;
}
}
}
return isRep;
}
#endregion
public void SetLog(Action log)
{
taskLog = log;
}
#region Tool Methonds
int GetTid()
{
lock (obj)
{
tid += 1;
//安全代码,以防万一(服务器)
while (true)
{
if (tid == int.MaxValue)
{
tid = 0;
}
//最后一个归0后从新赋值唯一id
bool used = false;
for (int i = 0; i < tids.Count; i++)
{
if (tid == tids[i])
{
used = true;
break;
}
}
if (!used)
{
break;
}
else
{
tid += 1;
}
}
}
return tid;
}
///
/// tid回收
///
void RecycleTid()
{
for (int i = 0; i < recTids.Count; i++)
{
int tid = recTids[i];
for (int j = 0; j < tids.Count; j++)
{
if (tids[j] == tid)
{
tids.RemoveAt(j);
break;
}
}
}
recTids.Clear();
}
void LogInfo(string info)
{
taskLog?.Invoke(info);
}
///
/// 获取时间的方法
///
///
double GetUTCMilliseconds()
{
//Now是本机时间
//现在世界标准时间-计算机元年时间
TimeSpan ts = DateTime.UtcNow - startDateTime;
//返回TimeSpan值表示的毫秒数
return ts.TotalMilliseconds;
}
#endregion
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
class Program
{
static void Main(string[] args)
{
//Test1();
//TimerTest();
Test2();
//阻塞让cw显示出来
Console.ReadKey();
}
///
/// 在独立线程检测并处理
///
private static void Test2()
{
PETimer pt = new PETimer(50);
pt.AddTimeTask(() => {
Console.WriteLine($"Time:{DateTime.Now}");
Console.WriteLine($"Process线程ID:{Thread.CurrentThread.ManagedThreadId.ToString()}");
}, 1000, 0);
}
private static void TimerTest()
{
//不声明会有二义性 每隔50毫秒循环一次 看线程ID 里面封装有一个线程池 看谁空闲调用谁
System.Timers.Timer t = new System.Timers.Timer(50);
t.AutoReset = true;//可以一直触发事件
t.Elapsed += (object sender, ElapsedEventArgs arg) => {
Console.WriteLine($"Time:{DateTime.Now}");
Console.WriteLine($"Process线程ID:{Thread.CurrentThread.ManagedThreadId.ToString()}");
};
t.Start();
}
///
/// 在主线程检测并处理
///
private static void Test1()
{
PETimer pt = new PETimer();
pt.SetLog((string info) => {
Console.WriteLine($"ConsoleLog{info}");
});
pt.AddTimeTask(() => {
Console.WriteLine($"Time:{DateTime.Now}");
Console.WriteLine($"Process线程ID:{Thread.CurrentThread.ManagedThreadId.ToString()}");
},1000,0);
while (true)
{
pt.Update();
//休眠20毫秒 不然CPU占用率高
Thread.Sleep(20);
}
}
}
然后就OK了
image.png
然后因为多线程 加上锁 把数据做安全一点 不然不同线程同时修改就当机了 当然也可能死锁发生
using System.Collections.Generic;
using System;
using System.Timers;
public class PETimeTask
{
public int tid;
public double destTime;//单位:毫秒
public Action callBack;
public double delay;
public int count;//次数
public PETimeTask(int tid, double destTime, Action callBack, double delay, int count)
{
this.tid = tid;
this.destTime = destTime;
this.callBack = callBack;
this.count = count;
this.delay = delay;
}
}
public class PEFrameTask
{
public int tid;
public int destFrame;//单位:毫秒
public Action callBack;
public int delay;
public int count;//次数
public PEFrameTask(int tid, int destFrame, Action callBack, int delay, int count)
{
this.tid = tid;
this.destFrame = destFrame;
this.callBack = callBack;
this.count = count;
this.delay = delay;
}
}
public enum EPETimeUnit
{
Millisecond = 0,
Second,
Minute,
Hour,
Day
}
///
/// 支持时间定时,帧定时
/// 定时任务可循环 取消 替换
///
public class PETimer
{
Action taskLog;
Action, int> taskHandle;
//声明锁
static readonly string lockTid = "lockTid";
//C#的计时 计算机元年
DateTime startDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
double nowTime;
Timer srvTimer;
int tid;
List tids = new List();
///
/// tid缓存回收
///
List recTids = new List();
static readonly string lockTime = "lockTime";
///
/// 临时列表 支持多线程操作 错开时间操作 避免使用锁 提升操作效率
///
List tmpTimes = new List();
List taskTimes = new List();
List tmpDelTimes = new List();
int frameCounter;
static readonly string lockFrame = "lockFrame";
List tmpFrames = new List();
List taskFrames = new List();
List tmpDelFrames = new List();
///
///
///
/// 调用运行间隔服务器用
public PETimer(int interval = 0)
{
if (interval != 0)
{
srvTimer = new Timer(interval)
{
AutoReset = true //设置是否循环
};
srvTimer.Elapsed += (object sender, ElapsedEventArgs arg) =>
{
Update();
};
srvTimer.Start();
}
}
public void Update()
{
CheckTimeTask();
CheckFrameTask();
DelTimeTask();
DelFrameTask();
if (recTids.Count > 0)
{
lock (lockTid)
RecycleTid();
}
}
void DelFrameTask()
{
if (tmpDelFrames.Count > 0)
{
lock (lockFrame)
{
for (int i = 0; i < tmpDelFrames.Count; i++)
{
bool isDel = false;
int delTid = tmpDelFrames[i];
for (int j = 0; j < taskFrames.Count; j++)
{
if (taskFrames[i].tid == delTid)
{
taskFrames.RemoveAt(j);
recTids.Add(delTid);
isDel = true;
LogInfo("Del taskTimeList ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
break;
}
}
if (isDel)
{
continue;
}
for (int j = 0; j < tmpFrames.Count; j++)
{
if (tmpFrames[i].tid == delTid)
{
tmpFrames.RemoveAt(j);
recTids.Add(delTid);
LogInfo("Del tmpTimeList ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
}
}
}
tmpDelFrames.Clear();
}
}
}
void DelTimeTask()
{
if (tmpDelTimes.Count > 0)
{
lock (lockTime)
{
for (int i = 0; i < tmpDelTimes.Count; i++)
{
bool isDel = false;
int delTid = tmpDelTimes[i];
for (int j = 0; j < taskTimes.Count; j++)
{
if (taskTimes[i].tid == delTid)
{
taskTimes.RemoveAt(j);
recTids.Add(delTid);
isDel = true;
LogInfo("Del taskTimeList ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
break;
}
}
if (isDel)
{
continue;
}
for (int j = 0; j < tmpTimes.Count; j++)
{
if (tmpTimes[i].tid == delTid)
{
tmpTimes.RemoveAt(j);
recTids.Add(delTid);
LogInfo("Del tmpTimeList ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
}
}
}
tmpDelTimes.Clear();
}
}
}
void CheckTimeTask()
{
//增加临时列表 因为服务器循环比update快 为了数据安全
if (tmpTimes.Count > 0)
{
lock (lockTime)
{
//加入缓存区中的定时任务
for (int i = 0; i < tmpTimes.Count; i++)
{
taskTimes.Add(tmpTimes[i]);
}
tmpTimes.Clear();
}
}
nowTime = GetUTCMilliseconds();
//遍历检测任务是否到达条件
for (int i = 0; i < taskTimes.Count; i++)
{
PETimeTask task = taskTimes[i];
//nowTime>task.destTime 1 nowTime
if (nowTime.CompareTo(task.destTime) < 0)
{
continue;
}
else
{
try
{
if (taskHandle != null)
{
taskHandle(task.callBack, task.tid);
}
else
{
//时间到 callBack不为空调用
task.callBack?.Invoke(task.tid);
}
}
catch (Exception e)
{
LogInfo(e.ToString());
}
if (task.count == 1)
{
taskTimes.RemoveAt(i);
i--;
recTids.Add(task.tid);
}
else
{
if (task.count != 0)
{
task.count -= 1;
}
//重新赋值时间
task.destTime += task.delay;
}
}
}
}
void CheckFrameTask()
{
if (tmpFrames.Count > 0)
{
lock (lockFrame)
{
//加入缓存区中的定时任务
for (int i = 0; i < tmpFrames.Count; i++)
{
taskFrames.Add(tmpFrames[i]);
}
tmpFrames.Clear();
}
}
frameCounter += 1;
//遍历检测任务是否到达条件
for (int i = 0; i < taskFrames.Count; i++)
{
PEFrameTask task = taskFrames[i];
if (frameCounter < task.destFrame)
{
continue;
}
else
{
try
{
if (taskHandle != null)
{
taskHandle(task.callBack, task.tid);
}
else
{
//时间到 callBack不为空调用
task.callBack?.Invoke(task.tid);
}
}
catch (Exception e)
{
LogInfo(e.ToString());
}
if (task.count == 1)
{
taskFrames.RemoveAt(i);
i--;
recTids.Add(task.tid);
}
else
{
if (task.count != 0)
{
task.count -= 1;
}
//重新赋值时间
task.destFrame += task.delay;
}
}
}
}
#region TimeTask
///
/// 添加一个计时器
///
///
///
///
///
///
public int AddTimeTask(Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)
{
ChangeTimeWithType(ref delay, timeUnit);
int tid = GetTid();
//从游戏开始到现在的时间
nowTime = GetUTCMilliseconds();
lock (lockTime)
tmpTimes.Add(new PETimeTask(tid, nowTime + delay, callBack, delay, count));
return tid;
}
///
/// 移除一个计时器
///
///
///
public void DeleteTimeTask(int tid)
{
lock (lockTime)
{
tmpDelTimes.Add(tid);
LogInfo("TmpDel ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
}
}
///
/// 替换 不涉及数据增删不用去改 自己改的慢就完蛋
///
///
///
///
///
///
///
public bool ReplaceTimeTask(int tid, Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)
{
ChangeTimeWithType(ref delay, timeUnit);
//从游戏开始到现在的时间
nowTime = GetUTCMilliseconds();
PETimeTask newTask = new PETimeTask(tid, nowTime + delay, callBack, delay, count);
bool isRep = false;
for (int i = 0; i < taskTimes.Count; i++)
{
if (taskTimes[i].tid == tid)
{
taskTimes[i] = newTask;
isRep = true;
break;
}
}
if (!isRep)
{
for (int i = 0; i < tmpTimes.Count; i++)
{
if (tmpTimes[i].tid == tid)
{
tmpTimes[i] = newTask;
isRep = true;
break;
}
}
}
return isRep;
}
#endregion
#region FrameTask
///
/// 添加一个帧计时器
///
///
///
///
///
///
public int AddFrameTask(Action callBack, int delay, int count = 1)
{
int tid = GetTid();
lock (lockFrame)
taskFrames.Add(new PEFrameTask(tid, frameCounter + delay, callBack, delay, count));
return tid;
}
///
/// 移除一个帧计时器
///
///
///
public void DeleteFrameTask(int tid)
{
lock (lockFrame)
{
tmpDelFrames.Add(tid);
}
}
///
/// 替换帧计时器
///
///
///
///
///
///
///
public bool ReplaceFrameTask(int tid, Action callBack, int delay, int count = 1)
{
PEFrameTask newTask = new PEFrameTask(tid, frameCounter + delay, callBack, delay, count);
bool isRep = false;
for (int i = 0; i < taskFrames.Count; i++)
{
if (taskFrames[i].tid == tid)
{
taskFrames[i] = newTask;
isRep = true;
break;
}
}
if (!isRep)
{
for (int i = 0; i < tmpFrames.Count; i++)
{
if (tmpFrames[i].tid == tid)
{
tmpFrames[i] = newTask;
isRep = true;
break;
}
}
}
return isRep;
}
#endregion
public void SetLog(Action log)
{
taskLog = log;
}
public void SetHandle(Action, int> handle)
{
taskHandle = handle;
}
///
/// 重置
///
public void Reset()
{
tid = 0;
tids.Clear();
recTids.Clear();
tmpTimes.Clear();
taskTimes.Clear();
tmpFrames.Clear();
taskFrames.Clear();
taskLog = null;
srvTimer.Stop();
}
//累加而不是 now now的话打断点也会变化
public DateTime GetLocalDateTime()
{
return TimeZone.CurrentTimeZone.ToLocalTime(startDateTime.AddMilliseconds(nowTime));
}
public double GetMillisendsTime()
{
return nowTime;
}
public int GetYear()
{
return GetLocalDateTime().Year;
}
public int GetMonth()
{
return GetLocalDateTime().Month;
}
public int GetDay()
{
return GetLocalDateTime().Day;
}
public int GetDayOfWeek()
{
return (int)GetLocalDateTime().DayOfWeek;
}
public string GetLocalTimeStr()
{
DateTime dt = GetLocalDateTime();
string str = $"{GetTimeStr(dt.Hour)}:{GetTimeStr(dt.Minute)}:{GetTimeStr(dt.Second)}";
return str;
}
#region Tool Methonds
int GetTid()
{
lock (lockTid)
{
tid += 1;
//安全代码,以防万一(服务器)
while (true)
{
if (tid == int.MaxValue)
{
tid = 0;
}
//最后一个归0后从新赋值唯一id
bool used = false;
for (int i = 0; i < tids.Count; i++)
{
if (tid == tids[i])
{
used = true;
break;
}
}
if (!used)
{
tids.Add(tid);
break;
}
else
{
tid += 1;
}
}
}
return tid;
}
///
/// tid回收
///
void RecycleTid()
{
for (int i = 0; i < recTids.Count; i++)
{
int tid = recTids[i];
for (int j = 0; j < tids.Count; j++)
{
if (tids[j] == tid)
{
tids.RemoveAt(j);
break;
}
}
}
recTids.Clear();
}
void LogInfo(string info)
{
taskLog?.Invoke(info);
}
///
/// 获取时间的方法
///
///
double GetUTCMilliseconds()
{
//Now是本机时间
//现在世界标准时间-计算机元年时间
TimeSpan ts = DateTime.UtcNow - startDateTime;
//返回TimeSpan值表示的毫秒数
return ts.TotalMilliseconds;
}
void ChangeTimeWithType(ref float delay, EPETimeUnit timeUnit)
{
//时间单位换算 最小毫秒
if (timeUnit != EPETimeUnit.Millisecond)
{
switch (timeUnit)
{
case EPETimeUnit.Second:
delay = delay * 1000;
break;
case EPETimeUnit.Minute:
delay = delay * 1000 * 60;
break;
case EPETimeUnit.Hour:
delay = delay * 1000 * 60 * 60;
break;
case EPETimeUnit.Day:
delay = delay * 1000 * 60 * 60 * 24;
break;
default:
LogInfo("Add Task TimeUnit Type error");
break;
}
}
}
string GetTimeStr(int time)
{
if (time < 10)
{
return $"0{time}";
}
else
{
return time.ToString();
}
}
#endregion
}
image.png
然后我自己优化了下很简单的 没用泛型反射因为这样会影响性能 毕竟服务器可是管所有客户端 客户端的计时器优化差点也没问题
这个是源码
https://github.com/1004019267/PETimer/tree/master