简体   繁体   English

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

[英]How can I execute different methods on different intervals of time with the same timer

I used timer.elapsed but this one just can call methods with the same interval of time for example 我使用了timer.elapsed,但是例如,它只能以相同的时间间隔调用方法

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

this call first and second every 1 second and i need call one at 3 seconds and the other at 5 seconds. 此电话每隔1秒进行一次和第二次通话,而我需要在3秒内拨打一次,在5秒内拨打另一个。

You can simply use multiple timers. 您可以简单地使用多个计时器。

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

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

如果您真的不能添加多个计时器(为什么不这样做),只需计算两个间隔的最大公约数(GCD)(例如,如果一个函数需要每30秒执行一次,而一个函数需要每45秒执行一次,那么GCD为5秒钟,因此将计时器设置为每5秒钟触发一次,但应每6秒钟启动一次计时器启动一次FunctionA,并每9秒钟执行一次FunctionB。

If you really want to do it using just a single timer: 如果您真的想仅使用一个计时器来执行此操作:

You will need to maintain a list in which each entry contains a reference to the method to call, and the time at which it should be invoked. 您将需要维护一个列表,其中每个条目都包含对要调用的方法的引用以及应调用该方法的时间。 (Must use absolute time values for this, not intervals.) (为此,必须使用绝对时间值,而不是时间间隔。)

  1. Walk through the list, find the entry with the smallest time value, (the time that is closest to now,) and set the timer to fire at that point in time. 浏览列表,找到时间值最小的条目(最接近现在的时间),并将计时器设置为在该时间点触发。

  2. When the timer fires, walk through the list again, and invoke any methods whose time-to-invoke is less-than-or-equal to now. 当计时器触发时,再次遍历该列表,并调用其调用时间小于或等于现在的任何方法。 For each method invoked, calculate the next time-to-invoke that method. 对于每个调用的方法,计算下一个调用该方法的时间。

  3. Go to step 1. 转到步骤1。

In doing so, you will essentially be re-implementing the timer mechanism of the .Net runtime, which is an exercise in futility. 这样,您实际上将重新实现.Net运行时的计时器机制,这是徒劳的。 So, you would be much better off not doing it this way, and using multiple timers instead. 因此,最好不要采用这种方式,而应使用多个计时器。

I'm not really sure why you'd want to do this, but you could do something similar to the following: 我不太确定为什么要这么做,但是可以做类似以下的事情:

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

And a way to use it: 以及使用方法:

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

I've barely tested this and I haven't spent too much time thinking about all the implications of the multithreading going on and the required locking / synchronisation, so take this code as a very preliminary approach. 我几乎没有对此进行过测试,也没有花太多时间考虑正在进行的多线程以及所需的锁定/同步的所有隐患,因此请将此代码作为一种非常初步的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在不同的时间间隔内使用相同的计时器? - How to use same timer for different time intervals? 定时器+显示消息+不同的时间间隔 - Timer + display messages + Different time intervals 以不同的时间间隔同时执行两种不同的方法 c# - Execute two different method simultaneously with different time intervals c# 如何从同一视图执行3种不同的控制器方法 - How to execute 3 different controller methods from the same view 如何同时锁定同一类的2种不同方法? - How to lock 2 different methods of the same class in the same time? 如何在同一个控制器中使用不同的参数调用不同的GET方法? - How can I call different GET Methods in the same Controller utilizing different parameters? 我如何才能同时登录相同的网站,不同的帐户,不同的代理? - How can I login to the same website, different accounts, different proxies, at the same time? Unity - 如何同时运行 2 个不同的 IEnumerator 方法? - Unity - How to run 2 different IEnumerator Methods at the same time? 如何在不同的时间间隔有效地 ping 不同的设备 - How to ping different devices at different time intervals efficiently 两个或更多个具有不同间隔的C#计时器 - two or more timer with different intervals with C#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM