Шаблон наблюдателя с таймером - PullRequest
3 голосов
/ 13 апреля 2011

Я использовал шаблон наблюдателя для своего приложения.

У меня есть субъект, в котором есть один System.Timers.Timer объект с именем 'tmr' .Тиковое событие этого таймера срабатывает через каждые 60 секунд .Об этом событии я буду уведомлять всех своих наблюдателей, которые прикреплены к моей теме.Я использовал цикл for для итераций в моем списке наблюдателей, а затем запустил метод обновления наблюдателей.

Предположим, у меня есть 10 наблюдателей, прикрепленных к моему предмету.

Каждому наблюдателю для завершения требуется 10 секунд.его обработка.

Теперь уведомление, выполняемое в цикле for, заставляет последний метод Update Observer вызываться через 90 секунд.то есть метод обновления следующего наблюдателя вызывается только после того, как предыдущий завершил свою обработку.

Но это не то, что я хотел в моем приложении.Мне нужно, чтобы все мои методы обновления наблюдателей запускались мгновенно при срабатывании таймера.Так что ни один наблюдатель не должен ждать.Я надеюсь, что это может быть сделано Threading.

Итак, я изменил код на,

// Fires the updates instantly
    public void Notify()
    {
      foreach (Observer o in _observers)
      {
        Threading.Thread oThread = new Threading.Thread(o.Update);
        oThread.Name = o.GetType().Name;
        oThread.Start();
      }
    }

Но у меня есть два сомнения в моем уме:

  1. Если есть 10 наблюдателей И мойинтервал таймера составляет 60 секунд. Тогда оператор new Thread () будет запускаться 600 раз.

    Эффективно ли и рекомендуется ли создавать новые потоки на каждом такте таймера?

  2. Что, если мои наблюдатели тратят слишком много времени на завершение своей логики обновления, т.е.60seconds.Означает, что отметка таймера происходит перед обновлением наблюдателей.Как я могу контролировать это?

Я могу опубликовать образец кода .. если требуется ...

Код, который я использовал ..

using System;
using System.Collections.Generic;
using System.Timers;
using System.Text;
using Threading = System.Threading;
using System.ComponentModel;

namespace singletimers
{
  class Program
  {


    static void Main(string[] args)
    {
      DataPullerSubject.Instance.Attach(Observer1.Instance);
      DataPullerSubject.Instance.Attach(Observer2.Instance);
      Console.ReadKey();
    }
  }

  public sealed class DataPullerSubject
  {
    private static volatile DataPullerSubject instance;
    private static object syncRoot = new Object();
    public static DataPullerSubject Instance
    {
      get
      {
        if (instance == null)
        {
          lock (syncRoot)
          {
            if (instance == null)
              instance = new DataPullerSubject();
          }
        }

        return instance;
      }
    }

    int interval = 10 * 1000;
    Timer tmr;
    private List<Observer> _observers = new List<Observer>();

    DataPullerSubject()
    {
      tmr = new Timer();
      tmr.Interval = 1; // first time to call instantly
      tmr.Elapsed += new ElapsedEventHandler(tmr_Elapsed);
      tmr.Start();
    }

    public void Attach(Observer observer)
    {
      _observers.Add(observer);
    }

    public void Detach(Observer observer)
    {
      _observers.Remove(observer);
    }

    // Fires the updates instantly
    public void Notify()
    {
      foreach (Observer o in _observers)
      {
        Threading.Thread oThread = new Threading.Thread(o.Update);
        oThread.Name = o.GetType().Name;
        oThread.Start();
      }
    }

    private void tmr_Elapsed(object source, ElapsedEventArgs e)
    {
      tmr.Interval = interval;
      tmr.Stop(); // stop the timer until all notification triggered
      this.Notify();
      tmr.Start();//start again
    }
  }


  public abstract class Observer
  {
    string data;
    public abstract void Update();
    public virtual void GetDataFromDBAndSetToDataSet(string param)
    {
      Console.WriteLine("Processing for: " + param);
      data = param + new Random().Next(1, 2000);
      Threading.Thread.Sleep(10 * 1000);//long work
      Console.WriteLine("Data set for: " + param);
    }
  }


  public sealed class Observer1 : Observer
  {
    private static volatile Observer1 instance;
    private static object syncRoot = new Object();
    public static Observer1 Instance
    {
      get
      {
        if (instance == null)
        {
          lock (syncRoot)
          {
            if (instance == null)
              instance = new Observer1();
          }
        }

        return instance;
      }
    }
    Observer1()
    {
    }
    public override void Update()
    {
      base.GetDataFromDBAndSetToDataSet("Observer1");
    }

  }

  public sealed class Observer2 : Observer
  {
    private static volatile Observer2 instance;
    private static object syncRoot = new Object();
    public static Observer2 Instance
    {
      get
      {
        if (instance == null)
        {
          lock (syncRoot)
          {
            if (instance == null)
              instance = new Observer2();
          }
        }

        return instance;
      }
    }
    Observer2()
    {
    }
    public override void Update()
    {
      base.GetDataFromDBAndSetToDataSet("Observer2");
    }

  }
}

Спасибо и всего наилучшего.

Ответы [ 3 ]

1 голос
/ 13 апреля 2011
  • Использование new Thread не рекомендуется.Используйте Task или Task<T>
  • Ваша лучшая попытка создания наблюдаемой структуры шаблона, вероятно, приблизится к Rx .Используйте то, что решает проблемы, которые вы упомянули (например, если обработка занимает слишком много времени). Rx даст вам огромную гибкость в определении ваших наблюдаемых сценариев.
0 голосов
/ 13 апреля 2011

В качестве альтернативы наблюдатели могут реализовать обновление неблокирующим способом.То есть обновление всегда возвращается сразу.Тогда объекты Observer обязаны выполнять свою работу в новом потоке, если это необходимо.

Я не уверен, поможет ли это в вашем сценарии - я не знаю, каковы ваши «Наблюдатели»,но тогда, может быть, вы тоже не знаете?

0 голосов
/ 13 апреля 2011

1) Вы можете использовать потоки из ThreadPool через ThreadPool.QueueUserWorkItem или можете использовать Задачи

2) Вам необходимо синхронизировать ваши методы .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...