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#中定时任务被阻塞问题的更多相关文章

  1. 解决一个C#中定时任务被阻塞问题

    解决一个C#中定时任务被阻塞问题 目录 解决一个C#中定时任务被阻塞问题 1.摘要 2.C#中定时任务的最简方法 3.定时任务阻塞现象 4.阻塞现象原因分析 5.问题解决 1.摘要 本文会介绍一个C# ...

  2. 在 tornado 中异步无阻塞的执行耗时任务

    在 tornado 中异步无阻塞的执行耗时任务 在 linux 上 tornado 是基于 epoll 的事件驱动框架,在网络事件上是无阻塞的.但是因为 tornado 自身是单线程的,所以如果我们在 ...

  3. Python中多线程的阻塞问题

    在使用Queue模块+多线程模拟生产者+消费者问题时,遇到了一个小问题,现在记录下来.供可能会遇到类似问题的初学者们参考. 该问题的完整参考代码如下.主要实现了以下的功能:在一个线程中,开启生产者模式 ...

  4. 如何解读 Java IO、NIO 中的同步阻塞与同步非阻塞?

    原文链接:如何解读 Java IO.NIO 中的同步阻塞与同步非阻塞? 一.前言 最近刚读完一本书:<Netty.Zookeeper.Redis 并发实战>,个人觉得 Netty 部分是写 ...

  5. Java问题:Quartz,Hibernate,Spring,Tomcat中定时任务无故停止,没有错误

    最近在做一个java项目的时候遇到一个十分奇怪的问题,想到大家可能也会遇到这样的问题,所以在此发出来,希望大家遇到的时候能够快速解决! 直入主题 问题:使用quartz进行定时任务自动执行的时候,用到 ...

  6. Java并发(10)- 简单聊聊JDK中的七大阻塞队列

    引言 JDK中除了上文提到的各种并发容器,还提供了丰富的阻塞队列.阻塞队列统一实现了BlockingQueue接口,BlockingQueue接口在java.util包Queue接口的基础上提供了pu ...

  7. SpringMVC中定时任务配置

    在项目中使用定时任务是常有的事,比如每天定时进行数据同步或者备份等等. 以前在从事C语言开发的时候,定时任务都是通过写个shell脚本,然后添加到linux定时任务中进行调度的. 现在使用Spring ...

  8. (4) Spring中定时任务Quartz集群配置学习

    原 来配置的Quartz是通过spring配置文件生效的,发现在非集群式的服务器上运行良好,但是将工程部署到水平集群服务器上去后改定时功能不能正常运 行,没有任何错误日志,于是从jar包.JDK版本. ...

  9. 转:PHP中实现非阻塞模式

    原文来自于:http://blog.csdn.net/linvo/article/details/5466046 程序非阻塞模式,这里也可以理解成并发.而并发又暂且可以分为网络请求并发 和本地并发 . ...

  10. Objc中触摸处理阻塞时消息派送的问题

    在游戏场景中添加了touchBegan的处理: -(void)touchBegan:(CCTouch *)touch withEvent:(CCTouchEvent *)event{ if ([sel ...

随机推荐

  1. 11月30日内容总结——前端简介、http协议概念、html协议概念及基础知识和部分标签的讲解

    目录 一.前端与后端的概念 什么是前端开发? 什么是后端? 学习前端的目的 前端三剑客 二.前端前戏 三.HTTP协议 1.四大特性 2.报文格式 3.响应状态码 四.HTML概览 1.HTML简介 ...

  2. Appium资源汇总

    Appium资源汇总 created: 2022-8-4 软件 网址 说明 https://github.com/appium/appium-inspector/releases 检查器的下载路径 h ...

  3. 【踩坑记录】docker启动报错mountpoint for cgroup not found

    具体报错信息: docker: Error response from daemon: OCI runtime create failed: container_linux.go:345: start ...

  4. 大佬们的博客 && 友链

    博客 1.https://wiki.kimleo.net/ 查组合子查到的,活化石级别 2.https://tech.meituan.com/ 美团博客,查函数式查到的,我还看过一篇讲aop的非常经典 ...

  5. wsl2 使用串口/usb

    wsl2串口 搜了几个方案,都不合适 网上很多人说wsl可以直接使用win的串口,com* 就对应 /dev/ttyS* 实际上这是wsl1的,wsl2官方明确表示不支持了 CH340 介绍 CH34 ...

  6. 谈谈Selenium中的三种切换之alert

    谈谈Selenium中的三种切换之alert 一.如何识别 识别方法:alert中的确定.取消.输入框无法用inspector定位到,当然还有一些特例. alert分为三种 alert confirm ...

  7. Quartz与Topshelf结合实现window定时服务

    一,新建控制台应用程序 二,选中项目,右键 - 管理 NuGet 程序包,添加四个: Quartz Quartz.Plugins Topshelf log4net 三,创建项目文件 三个配置文件:必须 ...

  8. 使用Docker搭建EPICS的IOC记录

    一直在centos使用KVM跑虚拟机搭建IOC,后来又使用zstack,web环境下管理虚拟机就更方便了. 最近电子源系统需要把束测系统跑起来,空间比较局促,不好放置服务器机柜.想着用一台工控机跑起来 ...

  9. 调用后台接口实现Excel导出功能以及导出乱码问题解决

    实现效果 在导出表格数据的时候,通常分为两种情况 页面列表数据导出 接口返回数据导出 这里主要介绍接口返回数据导出,关于页面的列表数据导出,请看另一篇:vue3+element表格数据导出 接口返回数 ...

  10. 部署Kubernetes v1.22.10高可用集群

    一.概述 Kubernetes集群控制平面(Master)节点右数据库服务(Etcd)+其它服务组件(Apiserver.Controller-manager.Scheduler等)组成:整个集群系统 ...