如何使用相同的计时器在不同的时间间隔上执行不同的方法

时间:2016-09-04 20:42:06

标签: c#

我使用了timer.elapsed但是这个只能调用具有相同时间间隔的方法,例如

timer.interval = 1000;
timer.elapsed += first();
timer.elapsed+=  second();

此呼叫每1秒钟第一次和第二次,我需要在3秒钟呼叫一个,另一个在5秒钟呼叫。

4 个答案:

答案 0 :(得分:1)

您可以简单地使用多个计时器。

 timer1.Inverval = 3000;
 timer1.Elapsed += first();

 timer2.Interval = 5000;
 timer2.Elapsed += second();

答案 1 :(得分:1)

如果你真的不能添加多个计时器,(为什么不呢?)只计算两个区间的最大公约数(GCD)(比如一个函数需要每30秒执行一次,一个需要每45秒执行一次,那么GCD是5秒,所以将定时器设置为每5秒触发一次,但是定时器开始时每6次执行一次FunctionA,而第9次执行功能B.

答案 2 :(得分:1)

如果真的想要只使用一个计时器来执行此操作:

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

  1. 浏览列表,找到时间值最小的条目(最接近现在的时间),并将计时器设置为在该时间点触发。

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

  3. 转到第1步。

  4. 这样做,你将基本上重新实现.Net运行时的计时器机制,这是徒劳的练习。所以,用这种方式做 会更好,而是使用多个计时器。

答案 3 :(得分:0)

我不确定你为什么要这样做,但你可以做类似以下的事情:

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();
}

我几乎没有对此进行测试,并且我没有花太多时间考虑多线程的所有影响以及所需的锁定/同步,因此请将此代码作为一种非常初步的方法。 / p>