观察者模式与计时器

时间:2011-04-13 11:08:16

标签: c# .net multithreading oop design-patterns

我已将Observer Pattern用于我的应用程序。

我有一个主题,其中有一个名为'tmr' System.Timers.Timer 对象。每个 60秒后,此计时器的tick事件将触发。在这个刻度事件中,我将通知所有与我的主题相关的观察者。我用了一个for循环来迭代我的Observers List&然后触发Observers Update方法。

假设我有10名观察员加入我的主题。

每个观察者需要10秒钟才能完成处理。

现在在for循环中完成通知会导致在90秒后调用最后一个Observer的Update方法。即,只有在前一个完成其处理后,才会调用Next Observer Update方法。

但这不是我想要的应用程序。我需要所有观察者更新方法在计时器滴答发生时立即触发。所以没有观察者必须等待。我希望通过线程可以做到这一点。

所以,我修改了代码,

// 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. 如果我的观察者花费太多时间来完成更新逻辑,即超过60秒,该怎么办?表示在更新观察者之前发生计时器滴答。我该如何控制这个?

  3. 我可以发布示例代码..如果需要......

    我使用的代码..

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

    谢谢&amp;亲切的问候。

3 个答案:

答案 0 :(得分:1)

  • 不鼓励使用new Thread。使用TaskTask<T>
  • 创建Observable模式框架的最佳尝试可能只接近Rx。使用它解决您提到的问题(即,如果处理花费太多时间)。 Rx将为您提供定义可观察场景的巨大灵活性。

答案 1 :(得分:0)

1)您可以通过ThreadPool.QueueUserWorkItem使用ThreadPool中的主题,也可以使用Tasks

2)你必须synchronize your Methods

答案 2 :(得分:0)

或者,观察者可以以非阻塞方式实现Update。 也就是说,Update总是立即返回。然后,Observer对象有责任在必要时在新线程中执行它们的工作。

我不确定这在你的情况下是否有帮助 - 我不知道你的'观察者'是什么,但那么也许你也不知道?