服务器的话就没有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)相关推荐

  1. 饥荒服务器模组全部显示冲突,饥荒联机版TGP多层世界服务端整合包及MOD添加设置教程_游戏堡...

    今天游戏堡小编为大家带来的是饥荒联机版TGP多层世界服务端整合包及MOD添加设置教程,还不清楚的玩家下面一起来看看吧! 下载地址:<饥荒联机版> TGP多层世界服务端整合包及MOD添加设置 ...

  2. 在以TCP为连接方式的服务器中,为什么在服务端设计当中需要考虑心跳?

    https://www.zhihu.com/question/35013918 在以TCP为连接方式的服务器中,为什么在服务端设计当中需要考虑心跳? 这个心跳包除了告知服务端我在线,还有其他作用吗?比 ...

  3. Unity网络斗地主 服务端

    Unity网络斗地主  服务端 @by梦想之家2工作室 阿龙 已经做好了服务器框架,并且能实现服务器给客户端分牌的问题! 转载于:https://www.cnblogs.com/alongu3d/p/ ...

  4. 梦幻默认服务器文件夹修改器,【梦幻仙境V3.96服务端】梦幻最新完美开心版带存档与修改器时代梦幻最新5.2版本...

    [梦幻仙境V3.96服务端]梦幻最新完美开心版带存档与修改器时代梦幻最新5.2版本 梦幻仙境这个版本智能玩到109级.玩过这个梦战系列改版的都知道.就不介绍了.因为作者太垃圾了.但是游戏可玩性还是很高 ...

  5. 武林外传 纯端 修改服务器,【武林外传单机一键服务端】某宝几百的最新星陨武林新春版 飞羽一键安装客户端带GM管理与刷物品工具...

    [武林外传单机一键服务端]某宝几百的最新星陨武林新春版 飞羽一键安装客户端带GM管理与刷物品工具 游戏特色内容 1.角色上线1级,点击新手宝箱可自动扩充背包仓库,并获得100金 2.专职涅槃羽化任务均 ...

  6. 传奇列表放在服务器哪个文件夹,传奇服务端目录文件详细说明

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 当我们下载1个传奇服务端的时候.主文件包是mirserver,那么我来给大家详细说下,这个文件包里面的全部文件夹的作用. MirServer(传奇服务端) ...

  7. 传奇服务器是测试模式怎么修改,www.23bb.net告诉你传奇服务端中默认系统提示文字修改方法...

    在玩传奇中中,常见一些系统提示,如人物在安全区中扔东西时,会弹出对话框提示禁止扔,或者在游戏登陆时提示攻击模式,及人物行会显示与夫妻称号显示格式等所有的系统默认格式.其实这些格式都是可以进行修改的,今 ...

  8. 我的世界怎么修改服务器路径,我的世界服务端java路径咋样设置?

    匿名用户 1级 2015-03-04 回答 "Java" -Xincgc -Xmx1G -jar "%BINDIR%\mcpc-plus-1.7.2-R0.4-forge ...

  9. 虚拟机+服务器管理器怎么打开,大话西游2特色版虚拟机镜像一键服务端+启动教程+物品ID+GM设置方法+数据库工具等...

    内容介绍2021-4-3,修复链接失效问题,下载已恢复. 2018年12月16日,更新修复无法进入系统桌面问题.重要说明:数据库工具解压时会报毒,如不修改可以无视,如需修改请关闭杀毒软件再解压,否则数 ...

最新文章

  1. 干货 | 详解对象检测模型中的Anchors
  2. 字符串数组-获取两个字符串中最大的相同子串(最大相同子串有且只有一个)
  3. 把一件简单的事情做好你就不简单了
  4. 微型计算机广告牌实验报告,微机原理课程设计报告
  5. maven+nexus搭建maven仓库
  6. android 类ios actionsheet效果
  7. VirtualBox LINUX虚拟机与WINDOWS共享文件夹
  8. Mybaits整个Spring项目,简单示例,10分钟快速上手
  9. 小程序 做二维码带logo绘制二维码
  10. X站全称是什么_科普|HDMI是什么意思?有什么用处?一文带你了解HDMI的发展史...
  11. python考拉兹猜想_Python练习题 042:Project Euler 014:最长的考拉兹序列
  12. Python学习:垃圾回收机制
  13. 网络信息化时代,3D产品建模宣传很到位
  14. 风场可视化与原理剖析
  15. javaweb mysql 连接池 c3p0 配置_javaWeb_JDBC_c3p0数据库连接池
  16. 寒冬已至?四面楚歌的Android工程师该何去何从
  17. Keil uVision5 Win10 设置字体 崩溃
  18. 2022 年合肥市经开区第七届青少年信息学竞赛 小学组试题
  19. 我想对雷军说:请做点实事为用户,别天天在微博上吹牛逼
  20. Pycharmpython安装教程

热门文章

  1. C++插入排序(附完整源码)
  2. html中怎么用js把表格清空_一款简洁非常好用的前端表格组件库
  3. 「Leetcode-Python」python中利用链表计算两个非负整数之和(链表类型非列表)
  4. 最简单的kafka demo案例
  5. 4.QPixmap,QTransform,绘图函数的使用
  6. Kettle使用_20 笛卡尔积与前一行后一行Lead Lag
  7. Mysql UTF8 varchar与Oracle ZHS16GBK varchar2同长度下存汉字的差异
  8. ubuntu16.04 在cuda9.0环境下编译安装opencv2.4.13.7
  9. MFC中字符间相互转换总结
  10. 高并发分布式系统中生成全局唯一(订单号)Id