定时修改列表 服务器版,Unity定时回调(服务端不依赖Update)
服务器的话就没有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
定时修改列表 服务器版,Unity定时回调(服务端不依赖Update)相关推荐
- 饥荒服务器模组全部显示冲突,饥荒联机版TGP多层世界服务端整合包及MOD添加设置教程_游戏堡...
今天游戏堡小编为大家带来的是饥荒联机版TGP多层世界服务端整合包及MOD添加设置教程,还不清楚的玩家下面一起来看看吧! 下载地址:<饥荒联机版> TGP多层世界服务端整合包及MOD添加设置 ...
- 在以TCP为连接方式的服务器中,为什么在服务端设计当中需要考虑心跳?
https://www.zhihu.com/question/35013918 在以TCP为连接方式的服务器中,为什么在服务端设计当中需要考虑心跳? 这个心跳包除了告知服务端我在线,还有其他作用吗?比 ...
- Unity网络斗地主 服务端
Unity网络斗地主 服务端 @by梦想之家2工作室 阿龙 已经做好了服务器框架,并且能实现服务器给客户端分牌的问题! 转载于:https://www.cnblogs.com/alongu3d/p/ ...
- 梦幻默认服务器文件夹修改器,【梦幻仙境V3.96服务端】梦幻最新完美开心版带存档与修改器时代梦幻最新5.2版本...
[梦幻仙境V3.96服务端]梦幻最新完美开心版带存档与修改器时代梦幻最新5.2版本 梦幻仙境这个版本智能玩到109级.玩过这个梦战系列改版的都知道.就不介绍了.因为作者太垃圾了.但是游戏可玩性还是很高 ...
- 武林外传 纯端 修改服务器,【武林外传单机一键服务端】某宝几百的最新星陨武林新春版 飞羽一键安装客户端带GM管理与刷物品工具...
[武林外传单机一键服务端]某宝几百的最新星陨武林新春版 飞羽一键安装客户端带GM管理与刷物品工具 游戏特色内容 1.角色上线1级,点击新手宝箱可自动扩充背包仓库,并获得100金 2.专职涅槃羽化任务均 ...
- 传奇列表放在服务器哪个文件夹,传奇服务端目录文件详细说明
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 当我们下载1个传奇服务端的时候.主文件包是mirserver,那么我来给大家详细说下,这个文件包里面的全部文件夹的作用. MirServer(传奇服务端) ...
- 传奇服务器是测试模式怎么修改,www.23bb.net告诉你传奇服务端中默认系统提示文字修改方法...
在玩传奇中中,常见一些系统提示,如人物在安全区中扔东西时,会弹出对话框提示禁止扔,或者在游戏登陆时提示攻击模式,及人物行会显示与夫妻称号显示格式等所有的系统默认格式.其实这些格式都是可以进行修改的,今 ...
- 我的世界怎么修改服务器路径,我的世界服务端java路径咋样设置?
匿名用户 1级 2015-03-04 回答 "Java" -Xincgc -Xmx1G -jar "%BINDIR%\mcpc-plus-1.7.2-R0.4-forge ...
- 虚拟机+服务器管理器怎么打开,大话西游2特色版虚拟机镜像一键服务端+启动教程+物品ID+GM设置方法+数据库工具等...
内容介绍2021-4-3,修复链接失效问题,下载已恢复. 2018年12月16日,更新修复无法进入系统桌面问题.重要说明:数据库工具解压时会报毒,如不修改可以无视,如需修改请关闭杀毒软件再解压,否则数 ...
最新文章
- 干货 | 详解对象检测模型中的Anchors
- 字符串数组-获取两个字符串中最大的相同子串(最大相同子串有且只有一个)
- 把一件简单的事情做好你就不简单了
- 微型计算机广告牌实验报告,微机原理课程设计报告
- maven+nexus搭建maven仓库
- android 类ios actionsheet效果
- VirtualBox LINUX虚拟机与WINDOWS共享文件夹
- Mybaits整个Spring项目,简单示例,10分钟快速上手
- 小程序 做二维码带logo绘制二维码
- X站全称是什么_科普|HDMI是什么意思?有什么用处?一文带你了解HDMI的发展史...
- python考拉兹猜想_Python练习题 042:Project Euler 014:最长的考拉兹序列
- Python学习:垃圾回收机制
- 网络信息化时代,3D产品建模宣传很到位
- 风场可视化与原理剖析
- javaweb mysql 连接池 c3p0 配置_javaWeb_JDBC_c3p0数据库连接池
- 寒冬已至?四面楚歌的Android工程师该何去何从
- Keil uVision5 Win10 设置字体 崩溃
- 2022 年合肥市经开区第七届青少年信息学竞赛 小学组试题
- 我想对雷军说:请做点实事为用户,别天天在微博上吹牛逼
- Pycharmpython安装教程
热门文章
- C++插入排序(附完整源码)
- html中怎么用js把表格清空_一款简洁非常好用的前端表格组件库
- 「Leetcode-Python」python中利用链表计算两个非负整数之和(链表类型非列表)
- 最简单的kafka demo案例
- 4.QPixmap,QTransform,绘图函数的使用
- Kettle使用_20 笛卡尔积与前一行后一行Lead Lag
- Mysql UTF8 varchar与Oracle ZHS16GBK varchar2同长度下存汉字的差异
- ubuntu16.04 在cuda9.0环境下编译安装opencv2.4.13.7
- MFC中字符间相互转换总结
- 高并发分布式系统中生成全局唯一(订单号)Id