服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#中定时任务被阻塞问题的解决方法

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

2022-12-08 11:28JerryMouseLi C#

这篇文章主要给大家介绍了关于C#中定时任务被阻塞问题的解决方法,文中通过示例代码介绍的非常详细,对大家学习或者使用c#具有一定的参考学习价值,需要的朋友可以参考下

1.摘要

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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,将一个工作项添加到线程池队列中,使你的回调方法得到调用。此方法有多个重载,具体读者可以自行去看。

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

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

3.定时任务阻塞现象

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

4.阻塞现象原因分析

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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#中定时任务被阻塞问题的解决方法

总结

到此这篇关于C#中定时任务被阻塞问题解决的文章就介绍到这了,更多相关C#定时任务被阻塞内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/JerryMouseLi/p/15543495.html

延伸 · 阅读

精彩推荐
  • C#超简单C#获取带汉字的字符串真实长度(单个英文长度为1,单个中文长度为2)

    超简单C#获取带汉字的字符串真实长度(单个英文长度为1,单个中

    正常情况下,我们是直接去string的length的,但是汉字是有两个字节的,所以直接用length是错的...

    wdc11692022-02-21
  • C#解答“60k”大佬的19道C#面试题(上)

    解答“60k”大佬的19道C#面试题(上)

    这篇文章主要解答了“60k”大佬的19道C#面试题中的10道,文中的面试题比较小众,作者给了不错的答案,相信对你以后的面试有所帮助,感兴趣就来了解下...

    .NET骚操作12082022-09-09
  • C#C#开发Windows窗体应用程序的简单操作步骤

    C#开发Windows窗体应用程序的简单操作步骤

    这篇文章主要介绍了C#开发Windows窗体应用程序的简单操作步骤,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    明日学院5292022-11-12
  • C#C#有效防止同一账号多次登录(附三种方法)

    C#有效防止同一账号多次登录(附三种方法)

    这篇文章主要介绍了C#有效防止同一账号多次登录的方法,有效防止同一账号多次登录的方法很多,比如用数据库来记录用户登录情况、用Application来保存用...

    熊灬孩灬子8582021-11-03
  • C#c# 委托的本质是什么

    c# 委托的本质是什么

    这篇文章主要介绍了c# 委托的本质是什么,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下...

    Learning hard11992022-09-28
  • C#C# WinFrom导出Excel过程解析

    C# WinFrom导出Excel过程解析

    这篇文章主要介绍了C#WinFrom导出Excel过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...

    最爱吃汤圆2710412022-08-08
  • C#C#控件Picturebox实现鼠标拖拽功能

    C#控件Picturebox实现鼠标拖拽功能

    这篇文章主要为大家详细介绍了C#控件Picturebox实现鼠标拖拽功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    Tomorrow Never Comes4192022-03-01
  • C#C# PictureBox图片控件实现图片交换

    C# PictureBox图片控件实现图片交换

    在c#中可以使用PictureBox控件来呈现图像,本文主要介绍了C# PictureBox实现图片交换,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    zs13420847768842022-11-23