如何以精确的间隔重复线程? C#

编程


C#
 private volatile bool _pause = false;
 private ManualResetEvent _pauseEvent = new ManualResetEvent(true);
 private Thread m_thread;
 private bool _istoday = true;
 private bool _isTimer_stop = false;
 private bool _thread_start = true;

private void btn_start_Click(object sender, EventArgs e)
 {

     int timer_interval = (int)numeric_app_freequency.Value;

         timer1_Tick(sender, e);
         timer1.Interval = 60 * 1000 * timer_interval;
         timer1.Enabled = true;
         timer1.Start(); //

 }

 private void timer1_Tick(object sender, EventArgs e)
 {
     if (_thread_start == true)
       {
         _thread_start = false;
         _istoday = true;
         m_thread = new Thread(new ThreadStart(begin_thread));
         m_thread.Name = "thred_1";
         m_thread.IsBackground = true;
         m_thread.Start();

        }

 }

 private void begin_thread()
 {

     int pageNum = 1;

     while (_pauseEvent.WaitOne())
     {
         if (_istoday == true)
         {

             parse_trs(pageNum);
             pageNum++;

         }
         else
         {
             Textbox1.Text = "Work is done"; ;
             break;
         }

     }
     _autoEvent.Set();
 }

 private void parse_trs(int pageNum)
 {
     string str_pageNum = pageNum.ToString();

     string list_url = "http://somedomain.com/bbs/board.php?bo_table=funny&page=" + str_pageNum;

     WebClient client = new WebClient();
     string sourceUrl = client.DownloadString(list_url);

     HtmlAgilityPack.HtmlDocument mydoc = new HtmlAgilityPack.HtmlDocument();

     mydoc.LoadHtml(sourceUrl);


     HtmlNodeCollection tr_col = mydoc.DocumentNode.SelectNodes("/ html / body//div[@id="bo_list"]//table/tbody/tr");

     foreach (HtmlNode node in tr_col)
     {

         _pauseEvent.WaitOne();


         if (post_date == today_date)
         {

             Do work.......................................

         }
         else
         {
             _istoday = false;
             break;
         }

     }
 }

我尝试过的:

我使用了 while 循环而不是计时器,但 CPU 过载,因此应用程序冻结

解决方案1

对于获得线程的一些周期性或近周期性行为,这可能是最糟糕的设计。 原因有很多,没有必要一一讨论。 创建新线程实例并启动它的成本是因素之一,但到目前为止,还不是最糟糕的。 最糟糕的是很容易搞砸一切。

更好的直接解决方案是仅创建一个附加线程并使其在几乎整个应用程序生命周期内保持执行。 您只需使其在“无限”循环中执行(实际上,仅在应用程序即将关闭时才中断),并通过使用事件等待句柄对象来限制其活动。

重要的是要了解在通话中 WaitHandle.WaitOne 线程要么通过,要么被放入特殊的 等待状态; 它被关闭并且永远不会被调度回执行,直到它被唤醒,这发生在 Thread.Abort, Thread.Interrupt、超时和其他事件,特别是从另一个线程发出等待句柄对象的信号。 这样,线程在等待状态下花费的 CPU 时间为零,没有自旋等待,也没有定期检查状态,什么都没有。

请参见: EventWaitHandle 类 (System.Threading)[^]。

请看我过去的回答:
使代码线程安全[^],
暂停正在运行的线程[^],
线程中的 ManualResetEvent 和 AutoResetEvent[^],
在 web 服务中运行一个永远不会终止的作业/线程/进程 (asp.net)[^]。

特别注意使用阻塞集合的替代相关技术; 它与您当前的问题无关,但理解它很重要。

现在,让我们回到计时器的“周期性”重复。 我不确定你是否需要这样。 一种替代方法是在线程中单独重复这段代码,获取当前的实时时间,例如: System.DateTime.Now、计算下次执行时间并调用 Thread.Sleep 具有适当的持续时间。 但是如果你真的需要一个计时器(同样,我不知道为什么),它唯一的功能就是通过调用来发送事件等待句柄 EventWaitHandle.Set(),这会唤醒等待此事件句柄实例的线程。 请注意,与某些方法的几乎任何其他调用不同,此调用是线程安全的。 另请注意,计时器事件发生在您不知道的某个线程中(除非非常糟糕) System.Windows.Forms.Timer 它会调用 UI 线程中的刻度处理程序,但这种“缓解”是它唯一的好处; 在大多数情况下,永远不应该使用它,因为时机非常糟糕)。

这两种技术都可以解决您可能面临的最大问题。 如果您开始某些处理,并且由上一个计时器滴答引起的处理尚未完成,会发生什么情况? 很难想象所有可能发生的混乱。 我建议的解决方案完全没有这个问题。

-SA

コメント

タイトルとURLをコピーしました