【问题】为什么 System.Timers.Timer 更改间隔时间后的第一次触发时间是设定时间的三倍?...

【问题】为什么 System.Timers.Timer 更改间隔时间后的第一次触发时间是设定时间的三倍?

独立观察员 2022 年 9 月 4 日

在编写 “Wifi 固定器 [1]” 程序时,按如下方式使用了定时器:

// 声明;
private Timer _Timer = new Timer() { Interval = 1, AutoReset = true };


// 设置处理方法;
_Timer.Elapsed += new ElapsedEventHandler(TimerHandler);


/// <summary>
/// 定时器任务
/// </summary>
private async void TimerHandler(object source, ElapsedEventArgs e)
{
    if (_Timer.Interval == 1) // 如果是第一次执行
    {
        _Timer.Interval = 1000 * Configs.CheckInterval; // 设置 Interval 为想要的间隔时间。
    }


    // 刷新连接状态;
    _profileRadio = GetProfileRadio(_fixedWifiPack);
    if (_profileRadio.IsConnected)
    {
        Console.WriteLine("该 Wifi 已连接,无需操作");
        return;
    }


    Console.WriteLine($" 即将尝试连接【{_fixedWifiPack.Ssid}】...");
    bool result = await NativeWifi.ConnectNetworkAsync(_fixedWifiPack.Interface.Id, _fixedWifiPack.ProfileName,
        _fixedWifiPack.BssType, TimeSpan.FromSeconds(5));
    Console.WriteLine($"连接结果:{(result ?" 成功 " : " 失败 ")}");
}


// 开启
if (_Timer.Enabled)
{
    Console.WriteLine($"目前监控已处于开启状态,无需重复操作");
    return;
}
_Timer.Start();
Console.WriteLine($"【开启监控成功】检测间隔时间为 {Configs.CheckInterval}s");


// 关闭
if (!_Timer.Enabled)
{
    Console.WriteLine($"目前监控已处于关闭状态,无需重复操作");
    return;
}
_Timer.Stop();
_Timer.Interval = 1;
Console.WriteLine($"【关闭监控成功】{Environment.NewLine}");

现象:

208ba402ee99f43ac3f4b4a4c726681a.png

也就是,Timer 的 Interval 初始以及停止时,都设置为 1,为的是启动的时候能马上触发一次。然后在第一次触发时修改 Interval 为需要的间隔时间,用作后续的触发间隔。然后问题就来了,修改间隔后的那次触发,距离启动时立马触发的那次,间隔时间达到了设定间隔时间的 3 倍,而且每次都是这样。

修改时间间隔的地方加上先停止后启动,问题依旧:

3c70293e034ff885ba0c730c5f234cd7.png

不使用异步方法,问题依旧:

2997b80a1f6fc698180de5058d37c916.png

怀疑是和线程池有关系,进而和 CPU 核心数有关,我这个是四核:

c546f91942d71422372baba5a4c79e91.png

使用 毫秒定时器 [2] 或 多媒体定时器 [3] 也还是同样的现象。

看到网上也有人遇到类似但不完全相同的问题(《System.Timers.Timer 非常不准确》[4]):

324aef420e8810e35752c01e778dfb75.png

可以看到,他是使用了并行计算所以出问题了,但是我这里并没有使用并行计算。

然后网上一个讨论帖(《System.Timers.Timer 为什么会失效??[5])是这样说的:

d6c44ce3cf8aee7821234420b75191c3.png

因为怀疑计时不准,所以有好多人自己封装调用 winmm.dll 中的 “多媒体计时器” 来形成自定义的定时器,我尝试了两种(上面提到过),问题还是一样,所以可能他们这种不能解决我遇到的问题。

总之,问题还没解决,所以大家有什么想法或方法,还请不吝赐教。

附 - 参考资料及整理的资料:

1、Wifi 固定器 代码:https://gitee.com/dlgcy/DLGCY_FixedWifi/tree/Blog20220904

2、毫秒定时器(整理版代码):https://gitee.com/dlgcy/dotnetcodes/blob/dlgcy/DotNet.Utilities/%E5%AE%9A%E6%97%B6%E5%99%A8/MillisecondTimer.cs

3、多媒体定时器(原始代码托管):https://gitee.com/dlgcy/dotnetcodes/blob/dlgcy/DotNet.Utilities/%E5%AE%9A%E6%97%B6%E5%99%A8/MultimediaTimer.cs

4、《System.Timers.Timer 非常不准确》:https://qa.1r1g.com/sf/ask/2286140321/

5、《System.Timers.Timer 为什么会失效??》:https://bbs.csdn.net/topics/90487784?list=764574

6、《Timer 计时不准确的解决方案 每次都重新调整,修正误差》(提到多媒体定时器的文章):https://www.cnblogs.com/chucklu/p/4673600.html

7、《Timer 计时不准确的问题及解决方法》(提到毫秒定时器的文章):https://www.cnblogs.com/dehai/p/4347061.html

C#

C#10 新特性 [调用方参数表达式] 解决了我七年前的困惑

【分享】C# 字节帮助类 ByteHelper

C# 在自定义的控制台输出重定向类中整合调用方信息

C# 枚举转列表

.NET

Windows 服务 同时启动多个服务

PostSharp 中 AOP 功能的简单使用

.NET SDK-Style 项目(Core、Standard、.NET5)中的版本号

将 .NET Framework 项目转换为 .NET Standard 项目

ASP.NET Core MVC 网站学习笔记

Unity 容器简单使用方法

Unity容器依赖注入之属性注入使用备忘

添加服务引用来使用WebService

作品

利用 C# 中的 FileSystemWatcher 制作一个文件夹监控小工具

使用 WPF 版简易 SIP 服务器向 GB28181 摄像头发送直播请求

下载中转加速器 VPSDownloader.NET(.NET Core 程序部署到 Linux 系统) 

『简易日志』NuGet 日志包 SimpleLogger

PDF 目录编辑器使用介绍

Winform

Winform 进度条弹窗和任务控制

Winform 通过 WebBrowser 与 JS 交互

这三种 Timer 都可以在 .NET Framework 中用来执行定时任务,但它们的实现方式和使用场景略有不同: 1. System.Windows.Forms.Timer System.Windows.Forms.Timer 是 Windows 窗体应用程序中常用的计时器,它是在 UI 线程上执行的,每隔一定时间触发 Tick 事件,可以用来执行一些与 UI 相关的任务,例如更新控件状态或显示动画效果等。由于它是在 UI 线程上执行的,所以不能用于长时间的计算和繁重的任务。 2. System.Timers.Timer System.Timers.Timer 是一个多线程计时器,它在一个单独的线程上执行,每隔一定时间触发 Elapsed 事件,可以用来执行一些不需要与 UI 相关的任务,例如后台数据处理、日志记录等。由于它是在一个单独的线程上执行的,所以可以用于长时间的计算和繁重的任务。 3. System.Threading.Timer System.Threading.Timer 是一个基于线程池的计时器,它在一个线程池线程上执行,每隔一定时间触发回调方法,可以用来执行一些不需要与 UI 相关的任务,例如后台数据处理、日志记录等。由于它是基于线程池的,所以比 System.Timers.Timer 更加轻量级,但不适用于长时间的计算和繁重的任务。 总结来说,System.Windows.Forms.Timer 适用于与 UI 相关的定时任务,System.Timers.Timer 和 System.Threading.Timer 适用于不需要与 UI 相关的定时任务,其中前者在一个单独的线程上执行,后者在一个线程池线程上执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值