我怎么能在不同的时间间隔用相同的计时器执行不同的方法

本文关键字:计时器 方法 执行 时间 怎么能 | 更新日期: 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)。

如果你真的想只用一个定时器:

您需要维护一个列表,其中每个条目包含对要调用的方法的引用,以及应该调用该方法的时间。(必须使用绝对时间值,而不是间隔)

  1. 遍历列表,找到时间值最小的条目(最接近现在的时间),并设置定时器在该时间点触发

  2. 当计时器触发时,再次遍历列表,并调用调用时间小于或等于现在的任何方法。对于每个被调用的方法,计算下一次调用该方法的时间。

这样做,你将本质上重新实现。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();
}

我几乎没有测试过这个,我没有花太多时间考虑多线程的所有含义和所需的锁定/同步,所以把这段代码作为一个非常初步的方法。