2016-05-24 1 views
4

У меня есть около 20 функций, некоторые из них должны быть уволены один раз в секунду, некоторые, 20 раз в секунду и другие два раза в минуту в настоящее время у меня есть что-то вроде этого:C# Правильный способ периодически активизирующих функции

   DateTime nowVar = DateTime.Now; 
       var lastExecutionFunc1 = nowVar; 
       var lastExecutionFunc2 = nowVar; 
       var lastExecutionFunc3 = nowVar; 
       var lastExecutionFunc4 = nowVar; 

     DateTime _now = DateTime.Now; 


       if ((_now - lastExecutionFunc1).TotalSeconds >= 0.1) 
         { 
          lastExecutionFunc1 = _now; 
          //dosomething 
         } 
       if ((_now - lastExecutionFunc2).TotalSeconds >= 0.5) 
         { 
          lastExecutionFunc2 = _now; 
          //do something else 
         } 
       if ((_now - lastExecutionFunc3).TotalSeconds >= 30) 
         { 
          lastExecutionFunc3 = _now; 
          //do something else 
         } 
..... 

Хотя это работает, я не могу не думать, что должен быть более элегантный способ сделать это. Создание var для хранения каждого исполнения делает основной вид действительно беспорядочным. Думаю, я мог бы использовать пару, но это тоже было бы не слишком хорошо.

Любые советы?

EDIT: Если вы хотите увидеть, чего я пытаюсь достичь, you can see the whole code here. На линии 525.

+6

Вы можете использовать класс Timer, https://msdn.microsoft.com/en-us/library/system.windows.forms.timer(v=vs.110).aspx – Adil

+0

насчет создания массива функций, которые затем можно напрямую подавать в обратный вызов по таймеру, исходя из возрастающего счетчика? – Robert

+0

Простейшим решением является использование [Timer Class] (https://msdn.microsoft.com/en-us/library/system.timers.timer%28v=vs.110%29.aspx) – shadow

ответ

3

Ниже представлен базовый планировщик с блокировкой синхронизации.

using System; 
using System.Collections.Generic; 
using System.Timers; 

namespace TimerUsage 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Scheduler scheduler = new Scheduler(); 
      scheduler.ScheduleMethod(100,() => Console.WriteLine("func1")); 
      scheduler.ScheduleMethod(200,() => Console.WriteLine("func2")); 
      scheduler.ScheduleMethod(300,() => Console.WriteLine("func3")); 
      scheduler.ScheduleMethod(1000,() => Console.WriteLine("func4")); 
      scheduler.Run(); 
      System.Threading.Thread.Sleep(10000); 
     } 

    } 

    public class Scheduler 
    { 
     private Dictionary<int, Row> _schedule = new Dictionary<int, Row>(); 

     public void ScheduleMethod(int interval, Action method) 
     { 
      Row row; 
      if (!_schedule.TryGetValue(interval, out row)) 
      { 
       row = new Row(interval); 
       _schedule[interval] = row; 
      } 
      row.AddMethod(method); 
     } 

     public void Run() 
     { 
      foreach (var item in _schedule) 
      { 
       item.Value.StartTimer(); 
      } 
     } 
    } 

    internal class Row 
    { 
     private object _syncLock = new object(); 
     private Timer _timer; 
     private List<Action> _methods = new List<Action>(); 

     public Row(int interval) 
     { 
      _timer = new System.Timers.Timer(interval); 
      _timer.Elapsed += ExecuteItems; 
     } 

     private void ExecuteItems(object sender, ElapsedEventArgs e) 
     { 
      lock (_syncLock) 
      { 
       foreach (var method in _methods) 
       { 
        method(); 
       } 
      } 
     } 

     public void AddMethod(Action method) 
     { 
      _methods.Add(method); 
     } 

     public void StartTimer() 
     { 
      _timer.Start(); 
     } 

    } 

} 
+0

Benim kullanım alanım için biraz fazla teferruatlı duruyor ama teşekkürler. – flanker

+0

Rica ederim. Class'ı kopyalayarak kolay bir şekilde kullanabilirsiniz, teferruat kısmı kullanım zorluğu oluşturmayacaktır. –

3

Вы написали петлю infinty для этих событий времени? Очень плохая практика. Если кто-либо из вас «что-то делает» длится долго, вся остальная функциональность (и основная программа) перестанет работать. Если ваши функции могут работать незаметно, пусть они работают без изменений и используют разные таймеры для каждого из них. Если некоторые функции являются исключительными, используйте семафоры (статические члены), чтобы избежать параллельной работы.

+0

Я не думаю, что здесь проблема. Наличие 20 таймеров в одной форме кажется пустой тратой ресурсов, когда один таймер может обрабатывать все 20 методов. Конечно, они должны быть «асинхронными» методами, если это возможно. –

+0

Да, они находятся в блоке while (true), но они работают над другим потоком, чем основная программа, и нет никакой возможности для какой-либо функции принимать более нескольких тактов. Они просто берут строку откуда-то и копируют ее в другую строку. – flanker

1

Вот один из способов сделать это:

Я создал класс, который связывает метод с его интервал, используя Action делегат:

public class ActionInvoker 
{ 
    private DateTime _LastRunTime; 
    private Action _Action; 
    private double _Interval; 

    public ActionInvoker(Action action, double interval) 
    { 
     _Action = action; 
     _Interval = interval; 
     _LastRunTime = DateTime.Now; 
    } 


    public void InvokeAction() 
    { 
     var now = DateTime.Now; 
     if ((now - _LastRunTime).TotalMilliseconds >= _Interval) 
     { 
      _LastRunTime = now; 
      _Action.Invoke(); 
     } 
    } 

Я добавил список ActionInvoker в качестве частного члена формы:

private List<ActionInvoker> _Actions; 

Теперь, в конструкторе формы, я сделал это:

_Actions = new List<ActionInvoker>(); 

_Actions.Add(new ActionInvoker(DoThis, 10000)); 
_Actions.Add(new ActionInvoker(DoThat, 3000)); 

Теперь у меня есть в обработчик событий Timer.Tick этот код:

foreach(var ai in _Actions) 
{ 
    ai.InvokeAction(); 
} 

Конечно, это только основные POC, вам нужно будет развивать его дальше, если вы хотите отправить параметры для методов или если ваши методы возвращают значения.

Также обратите внимание, что лучше использовать эти методы как async, чтобы предотвратить зависание пользовательского интерфейса до его завершения.

+0

Это похоже на хороший способ сделать это. Но я не уверен, что понимаю, как работает «Действие».Что я должен пройти? Btw, функции, которые я запускаю, не принимают никаких параметров и ничего не возвращают. Они просто изменяют некоторые глобалы. Я добавил ссылку на мой проект в исходном сообщении, если вы хотите увидеть код. – flanker

+0

Я отредактировал свой ответ, чтобы включить ссылку на страницу MSDN для делегата 'Action'. –

+0

Да, я кое-что прочитал о типе действия. Кажется очень полезным, интересно, как я до сих пор не замечал этого. Благодарю. – flanker

 Смежные вопросы

  • Нет связанных вопросов^_^