C#中定时任务被阻塞问题的解决方法

作者:JerryMouseLi 时间:2023-10-27 00:56:02 

目录
  • 1.摘要

  • 2.C#中定时任务的最简方法

  • 3.定时任务阻塞现象

  • 4.阻塞现象原因分析

  • 5.问题解决

  • 总结

1.摘要

本文会介绍一个C#中最简单定时任务的使用方法,以及会遇到的定时任务被阻塞现象,从笔者理解的角度分析原因。以及提供解决方案。

2.C#中定时任务的最简方法


 protected internal void PollClient()
 {
     int i=0;
     Timer t = new Timer(p => {
         i++;
         if (deviceContextList.Count > 0)
         {
             var deviceContext=GetDeviceContext("123456789");
                 SendMessage(messageList[i%7],deviceContext.tcpSession.writerContext);
             logger.Info("客户端数量:"+ deviceContextList.Count);        
         }
         else
         {
             logger.Info("客户端数量为0");
             Console.WriteLine("客户端数量为0");
         }              
     }, null, 0, 1000) ;          
 }

上面的timer方法提供于微软System.Threading命名空间。System.Threading.Timer 是由线程池调用的。所有的Timer对象只使用了一个线程来管理。这个线程知道下一个回调对象在什么时候到期。下一个回调对象到期时,线程就会唤醒,在内部调用ThreadPool 的 QueueUserWorkItem,将一个工作项添加到线程池队列中,使你的回调方法得到调用。此方法有多个重载,具体读者可以自行去看。


Timer(TimerCallback callback, object state, int dueTime, int period)

第一个参数callback是回调方法,第二个参数state可以传参给回调方法的参数,第三个参数dueTime是第一次执行回调函数的延时时间,单位毫秒,第四个参数period是调用回调函数的时间间隔。使用起来是不是特别方便,把你需要执行的定时任务放在回调方法中,可独立写成方法,也可像上面一样写成匿名方法的形式。

3.定时任务阻塞现象

当上述任务被执行了几千次以后,定时任务会阻塞,不再执行,也不再打印日志。并且上面的写法有缺陷,。如果回调方法的执行时间很长,计时器可能(在上个回调还没有完成的时候)再次触发。这可能造成多个线程池线程同时执行你的回调方法。并且线程切换也会造成诸多损耗时间。

4.阻塞现象原因分析

上面的方法中使用局部变量来创建指向一个线程定时器。因为局部变量会被GC回收,导致定时器失效。
具体改进如下:


static int i=0;
static Timer _timer = null;
       protected  void PollClient()
       {
            _timer = new Timer(TimerCallback, null, 1000, Timeout.Infinite) ;          
       }
   private void TimerCallback(object state)
   {
           try
           {
               i++;

if (deviceContextList.Count > 0)
               {
                   var deviceContext = GetDeviceContext("123456789");
                   SendMessage(messageList[i % 7], deviceContext.tcpSession.writerContext);
                   logger.Info("客户端数量:" + deviceContextList.Count + "循环次数:" + i);

}
               else
               {
                   logger.Info("客户端数量为0" + "循环次数:" + i);
                   Console.WriteLine("客户端数量为0" + "循环次数:" + i);
               }
           }
           catch (Exception e)
           {
               logger.Error("定时测试下发报文异常:" + e);
           }
           finally
           {
               _timer.Change( 1000, Timeout.Infinite);
           }
       }

将定时器与计数变量设置为static是为了定时器不被GC回收。定时任务执行完成之后再设置下次调用时间间隔是为了该任务不过多占用线程池中的线程,节省线程切换时间等。

5.问题解决

可以看到任务已经被执行了86665次,优化后不再被GC回收。

C#中定时任务被阻塞问题的解决方法

来源:https://www.cnblogs.com/JerryMouseLi/p/15543495.html

标签:c#,定时任务,阻塞
0
投稿

猜你喜欢

  • WPF TextBox和PasswordBox添加水印

    2021-09-30 16:06:02
  • C#数据结构之堆栈(Stack)实例详解

    2022-12-17 21:25:37
  • 解决SpringBoot运行Test时报错:SpringBoot Unable to find

    2021-11-15 16:48:56
  • Java调用.dll文件的方法

    2023-11-23 21:16:22
  • Android 8.0系统中通知栏的适配微技巧

    2022-01-30 17:12:43
  • 浅谈Java中的重载,重写,多态,静态绑定、动态绑定

    2023-10-10 02:40:05
  • C#实现自定义windows系统日志的方法

    2021-12-17 13:02:31
  • C语言头文件<string.h>函数详解

    2023-07-01 18:59:34
  • 基于selenium-java封装chrome、firefox、phantomjs实现爬虫

    2022-04-07 19:04:28
  • c#根据文件类型获取相关类型图标的方法代码

    2022-07-30 10:56:41
  • androidQ sd卡权限使用详解

    2021-09-27 17:38:51
  • Gradle的缓存路径修改的四种方法(小结)

    2021-11-09 11:05:51
  • Java元注解Retention代码示例介绍

    2023-10-21 02:32:32
  • Apache Commons fileUpload实现文件上传之一

    2022-12-06 12:36:48
  • SpringSecurity登录使用JSON格式数据的方法

    2021-09-10 21:40:40
  • C#中文随机数实现方法

    2023-12-07 20:56:30
  • C#通过链表实现队列的方法

    2023-06-19 15:14:17
  • 代码详解Java猴子选王问题(约瑟夫环)

    2023-09-16 07:33:43
  • Java创建和启动线程的两种方式实例分析

    2023-12-05 08:26:59
  • Java应用开源框架实现简易web搜索引擎

    2023-08-22 20:20:54
  • asp之家 软件编程 m.aspxhome.com