我怎么能在不同的时间间隔用相同的计时器执行不同的方法
本文关键字:计时器 方法 执行 时间 怎么能 | 更新日期: 2023-09-27 18:05:41
我使用定时器。经过时间,但是这个可以调用相同时间间隔的方法例如
timer.interval = 1000;
timer.elapsed += first();
timer.elapsed+= second();
这个调用第一个和第二个每1秒,我需要调用一个在3秒,另一个在5秒。
您可以简单地使用多个计时器。
timer1.Inverval = 3000;
timer1.Elapsed += first();
timer2.Interval = 5000;
timer2.Elapsed += second();
如果你真的不能添加多个计时器,(为什么不呢?)只需计算两个间隔的最大公约数(GCD)(假设一个函数需要每30秒执行一次,另一个函数需要每45秒执行一次,那么GCD是5秒,所以将计时器设置为每5秒触发一次,但是在计时器启动时每6次执行一次FunctionA,每9次执行一次functionB)。
如果你真的想只用一个定时器:
您需要维护一个列表,其中每个条目包含对要调用的方法的引用,以及应该调用该方法的时间。(必须使用绝对时间值,而不是间隔)
-
遍历列表,找到时间值最小的条目(最接近现在的时间),并设置定时器在该时间点触发
-
当计时器触发时,再次遍历列表,并调用调用时间小于或等于现在的任何方法。对于每个被调用的方法,计算下一次调用该方法的时间。
这样做,你将本质上重新实现。net运行时的计时器机制,这是徒劳的练习。因此,您最好使用而不是这样做,并使用多个计时器。
我不太确定您为什么要这样做,但是您可以做以下类似的事情:
public class MultiIntervalTimer: IDisposable
{
private readonly Timer innerTimer;
private readonly IReadOnlyDictionary<int, MultiIntervalTimerCallbackInfo> callbackInfos;
private long totalElapsedMiliseconds;
private readonly int innerTimerInterval;
private object syncRoot = new object();
private bool disposed;
public MultiIntervalTimer(Dictionary<int, MultiIntervalTimerCallbackInfo> callbacks, int dueTime)
{
if (callbacks == null)
throw new ArgumentNullException(nameof(callbacks));
var innerTimerCallback = new TimerCallback(innerCallback);
callbackInfos = new Dictionary<int, MultiIntervalTimerCallbackInfo>(callbacks);
innerTimerInterval = getGreatestCommonDivisor(callbacks.Keys);
innerTimer = new Timer(innerTimerCallback, null, dueTime, innerTimerInterval);
}
public void Dispose()
{
if (disposed)
return;
innerTimer.Dispose();
disposed = true;
}
private static int getGreatestCommonDivisor(IEnumerable<int> numbers)
{
Debug.Assert(numbers != null);
Debug.Assert(numbers.Any());
var numbersArray = numbers.ToArray();
if (numbersArray.Length == 1)
return numbersArray[0];
if (numbersArray.Length == 2)
return getGreatestCommonDivisor(numbersArray[0], numbersArray[1]);
var trimmedNumbersArray = new int[numbersArray.Length - 1];
Array.Copy(numbersArray, 1, trimmedNumbersArray, 0, trimmedNumbersArray.Length);
return getGreatestCommonDivisor(numbersArray[0], getGreatestCommonDivisor(trimmedNumbersArray));
}
private static int getGreatestCommonDivisor(int left, int right)
{
while (right != 0)
{
var temp = right;
right = left % right;
left = temp;
}
return left;
}
private void innerCallback(object state)
{
Debug.Assert(syncRoot != null);
Debug.Assert(!disposed);
var elapsed = 0L;
lock (syncRoot)
{
totalElapsedMiliseconds += innerTimerInterval;
elapsed = totalElapsedMiliseconds;
}
foreach (var callback in callbackInfos.Where(c => elapsed % c.Key == 0))
{
callback.Value?.Callback(callback.Value.State);
}
}
}
public class MultiIntervalTimerCallbackInfo
{
public MultiIntervalTimerCallbackInfo(TimerCallback callback, object state)
{
if (callback == null)
throw new ArgumentNullException(nameof(callback));
Callback = callback;
State = state;
}
public TimerCallback Callback { get; }
public object State { get; }
}
和使用方法:
public class State
{
public State()
:this(0)
{ }
private State(int count)
{
Count = count;
}
public int Count { get; private set; }
public void IncrementCount() => Count++;
}
public static void Main(string[] args)
{
var state = new State();
bool stop = false;
var intervalCallback1 = new MultiIntervalTimerCallbackInfo(new System.Threading.TimerCallback(c =>
{
Console.WriteLine($"Interval 1: Call #{state.Count}. Thread Id: {Thread.CurrentThread.ManagedThreadId}");
state.IncrementCount();
}), state);
var intervalCallback2 = new MultiIntervalTimerCallbackInfo(new System.Threading.TimerCallback(c =>
{
Console.WriteLine($"Interval 2: Call #{state.Count}. Thread Id: {Thread.CurrentThread.ManagedThreadId}");
state.IncrementCount();
}), state);
var intervalCallback3 = new MultiIntervalTimerCallbackInfo(new System.Threading.TimerCallback(c =>
{
Console.WriteLine($"Interval 3: Call #{state.Count}. Thread Id: {Thread.CurrentThread.ManagedThreadId}");
state.IncrementCount();
}), state);
var intervalCallback4 = new MultiIntervalTimerCallbackInfo(new System.Threading.TimerCallback(c =>
{
Console.WriteLine($"Interval 4: Call #{state.Count}. Thread Id: {Thread.CurrentThread.ManagedThreadId}.'r'n Exiting loop", state);
stop = true;
}), state);
var callbacks = new Dictionary<int, MultiIntervalTimerCallbackInfo>() { { 50, intervalCallback1 },
{ 100, intervalCallback2 },
{ 200, intervalCallback3 },
{ 2000, intervalCallback4 } };
using (var timer = new MultiIntervalTimer(callbacks, 1000))
{
while (!stop)
{
}
}
Console.WriteLine($"Total calls: {state.Count}.");
Console.ReadLine();
}
我几乎没有测试过这个,我没有花太多时间考虑多线程的所有含义和所需的锁定/同步,所以把这段代码作为一个非常初步的方法。