.NET中的三种Timer的区别和用法

详细——VS2015(2017)如何创建C ++ CLR Windows窗体应用程序 VS2017如何创建C ++ CLR Windows窗体应用程序 微软从VS2012起就希望用户使用C#或VB来创建Windows窗体应用程序,所以逐渐去掉了C ++ CLR 创建Windows窗体应用程序的功能。 本解决方案为手工解决方案,适合VS2013及以上所有版本。欢迎大家采用。 这个方法在优快云中已经有很多人解释过了,本人只是想尽可能详细的再说一下。 使用默认名称Project1创建一... 阅读详情

转自:http://space.itpub.net/12639172/viewspace-571197

最近正好做一个WEB中定期执行的程序,而.NET中有3个不同的定时器。所以正好研究研究。这3个定时器分别是: 

//1.实现按用户定义的时间间隔引发事件的计时器。此计时器最宜用于 Windows 窗体应用程序中,并且必须在窗口中使用。 
System.Windows.Forms.Timer 

// 2.提供以指定的时间间隔执行方法的机制。无法继承此类。 
System.Threading.Timer 

//3.在应用程序中生成定期事件。 
System.Timers.Timer 

这三个定时器位于不同的命名空间内,上面大概介绍了3个定时器的用途,其中第一个是只能在Windows窗体中使用的控件。在.NET1.1里面,第3个System.Timers.Timer,也是可以拖拽使用,而.NET2.0开始取消了,只能手动编写代码。而后2个没有限制制。下面通过具体的列子来看3个Timer的使用和区别,网上谈的很多,但基本都没有代码。 

一 System.Windows.Forms.Timer 

#region System.Windows.Forms.Timer 
public partial class Form1 : Form 
{ 
public Form1() 
{ 
InitializeComponent(); 
} 

int num = 0; 

private void Form_Timer_Tick(object sender, EventArgs e) 
{ 
label1.Text = (++num).ToString(); 
Thread.Sleep(3000); 
} 

private void button1_Click(object sender, EventArgs e) 
{ 
Form_Timer.Start(); 
} 

private void button2_Click(object sender, EventArgs e) 
{ 
Form_Timer.Stop(); 
} 
} 
#endregion 


上面这个是一个很简单的功能,在Form窗体上拖了一个System.Windows.Forms.Timer控件名字为Form_Timer,在属性窗中把Enable属性设置为Ture,Interval是定时器的间隔时间。双击这个控件就可以看到 Form_Timer_Tick方法。在这个方法中,我们让她不停的加一个数字并显示在窗体上,2个按钮提供了对计时器的控制功能。 

执行的时候你去点击其他窗体在回来,你会发现我们的窗体失去响应了。因为我们这里使用Thread.Sleep(3000);让当前线程挂起,而UI失去相应,说明了这里执行时候采用的是单线程。也就是执行定时器的线程就是UI线程。 

Timer 用于以用户定义的事件间隔触发事件。Windows 计时器是为单线程环境设计的,其中,UI 线程用于执行处理。它要求用户代码有一个可用的 UI 消息泵,而且总是在同一个线程中操作,或者将调用封送到另一个线程。 

在Timer内部定义的了一个Tick事件,我们前面双击这个控件时实际是增加了一行代码 

this.Form_Timer.Tick += new System.EventHandler(this.Form_Timer_Tick); 
这个应该明白,不明白的可以看我BLOG中有关委托和事件的文章。然后Windows将这个定时器与调用线程关联(UI线程)。当定时器触发时,Windows把一个定时器消息插入到线程消息队列中。调用线程执行一个消息泵提取消息,然后发送到回调方法中(这里的Form_Timer_Tick方法)。而这些都是单线程进行了,所以在执行回调方法时UI会假死。所以使用这个控件不宜执行计算受限或IO受限的代码,因为这样容易导致界面假死,而应该使用多线程调用的Timer。另外要注意的是这个控件时间精度不高,精度限定为 55 毫秒。我们把Interval设置为20ms,然后在start和stop方法中记录当前时,并计算出运行时间: 





从上面图可以看到程序执行了7.8S也就是 7800ms,而间隔时间是20ms,也就是最后显示数字应该是390左右,但只有250,显然是不准确的,不过按MSDN说的55ms的精度,7800ms应该只执行了140多次或更少。不知道这里是不是理解有问题。 

二 System.Timers.Timer 

接下来就看下另一个Timer,我们用他来改写上面的程序 

#region System.Windows.Forms.Timer 
public partial class Form1 : Form 
{ 
public Form1() 
{ 
InitializeComponent(); 
} 

int num = 0; 
DateTime time1 = new DateTime(); 
DateTime time2 = new DateTime(); 
//定义Timer 
System.Timers.Timer Timers_Timer = new System.Timers.Timer(); 

private void button1_Click(object sender, EventArgs e) 
{ 
//手动设置Timer,开始执行 
Timers_Timer.Interval = 20; 
Timers_Timer.Enabled = true; 
Timers_Timer.Elapsed += new System.Timers.ElapsedEventHandler(Timers_Timer_Elapsed); 
time1 = DateTime.Now; 
} 

void Timers_Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
{ 
label1.Text = Convert.ToString((++num)); //显示到lable 
Thread.Sleep(3000); 
} 

private void button2_Click(object sender, EventArgs e) 
{ 
//停止执行 
Timers_Timer.Enabled = false; 
time2 = DateTime.Now; 
MessageBox.Show(Convert.ToString(time2-time1)); 
} 
} 
#endregion


我们可以看到这个代码和前面使用Form.Timer的基本相同,不同的是我们是手动定义的对象,而不是通过拉控件。他也有Interval ,Enabled 等属性,作用和第一是一样的。不同的是他的事件名为Elapsed ,但是和上面的Tick一样,绑定一个委托的方法。只是这里我们是手动完成的。另外不同之处是Form.Timer我们可以用Stop和Start方法控制,而这里是通过Enable属性控制。但实际上也可以用Stop和Start方法,内部也是通过他自己的Enable来控制的。 

最大的不同就是上面的代码在调试时会报错,提示你"线程间操作无效: 从不是创建控件“label1”的线程访问它。"但如果你不调试直接运行是OK的,而且运行时你去拖动窗体会发现没有出现假死。从这里我们就可以知道这里的Timer的创建线程和执行线程不是同一个线程。也就是使用了多线程。Timer的创建线程是UI线程,而执行线程是TheardPool中的线程,所以不会假死,但调试的时候会报错,因为非控件的创建线程不能操作控件。但你可以直接运行,这里是VS05做了手脚。解决办法很多,用delegate.BeginInvoke()等等。这里介绍特有的一种方法,设置Timer的SynchronizingObject属性,Timers_Timer.SynchronizingObject = label1;这样的话,我们的话,调试运行时就不会报错了,但是设置了这个属性Timer就编程单线程调用了,就基本和第一个完全一样了。

Timer 是为在多线程环境中用于辅助线程而设计的。服务器计时器可以在线程间移动来处理引发的 Elapsed 事件,这样就可以比 Windows 计时器更精确地按时引发事件。Elapsed 事件在 ThreadPool 线程上引发。如果 Elapsed 事件的处理时间比 Interval 长,在另一个 ThreadPool 线程上将会再次引发此事件。因此,事件处理程序应当是可重入的。 

另外和前面不同的现象是每次加1后并没有停止3秒在显示。而是继续显示,只是速度稍慢。因为我们设置间隔为20ms,而执行时间为3s,所以会在20ms后在另一个线程中继续执行,而当前线程被挂起而已。关于计时器的精度,取消3s的挂起,发现结果和第一个基本一致。 

三 System.Threading.Timer 

继续用这个对象改造程序。 

#region System.Windows.Forms.Timer 
public partial class Form1 : Form 
{ 
public Form1() 
{ 
InitializeComponent(); 
} 

int num = 0; 
DateTime time1 = new DateTime(); 
DateTime time2 = new DateTime(); 
System.Threading.Timer Thread_Time; 

private void button1_Click(object sender, EventArgs e) 
{ 
//启动 
Thread_Time = new System.Threading.Timer(Thread_Timer_Method,null,0,20); 
time1 = DateTime.Now; 

} 

void Thread_Timer_Method(object o) 
{ 
label1.Text = Convert.ToString((++num)); 
System.Threading.Thread.Sleep(3000); 
} 

private void button2_Click(object sender, EventArgs e) 
{ 
//停止 
Thread_Time.Dispose(); 
time2 = DateTime.Now; 
MessageBox.Show(Convert.ToString(time2-time1)); 
} 
} 
#endregion 


用Threading.Timer时的方法,和前面就不太相同了,所以的参数全部在构造函数中进行了设置,而且可以设置启动时间。而且没有提供start和stop方法来控制计时器。而且是以一种回调方法的方式实现,而不是通过事件来实现的。他们之间还是有区别的。 

我们只有销毁掉对象来停止他。当你运行时,你会发现他和前面的Timers.Timer一样,是多线程的,主要表现在不会假死,调试运行报错。但跟让你奇怪的是,我们的代码竟然无法让她停止下来。调用了Dispose方法没有用。问题在那?然后有进行了 测试,修改了间隔时间为100,200,500,1000,3000,4000。这几种情况。发现当间隔为500ms以上是基本马上就停止了。而间隔时间相对执行时间越短,继续执行的时间越长。这应该是在间隔时间小于执行时间时多个线程运行造成的。因为所有的线程不是同时停止的。间隔越短,线程越多,所以执行次数越多。 



最后来看下这个对象另外一个特殊的地方。 

static void Main() 
{ 
Timer t = new Timer(Test,null,0,1000); 
Console.ReadLine(); 
} 

public static void Test(object o) 
{ 
Console.WriteLine("nihao"); 
GC.Collect(); 
} 


这段代码会输出什么结果呢?默认情况他只输出一次,就停止了。为什么呢?根据上面说的,当定义对象t,执行代码后,进行了强制垃圾回收,因为t在Main中没有其他引用,所以被回收掉了。但是如果我们吧编译器的”优化“项取消掉,在看看情况。程序进然一直在输出。为什么执行垃圾回收却没有被回收呢?因为这个禁用优化选项,t的声明周期被扩展到了方法结束。所以一直执行。 

因为编译器默认是优化的,所以我们必须保证Timer对象一直被引用,而避免被垃圾回收。所以我们可以在编译器打开优化的情况下,在Main函数最后加上t=null保证回收前被引用,但你发现,这样是没用的。因为JIT编译器优化后会吧t=null直接删除,所以我们用t.Dispose(),就可以达到目的。在我们进行垃圾回收时,CLR发现t还有被引用,还没执行Dispose所以不会被回收。是以Threading.Timer有时候会出现运行一次就停止或者是销毁了还在运行的情况,而且和编译器优化也有关,所以使用时要注意。 

最后看下MSDN的描述: 只要在使用 Timer,就必须保留对它的引用。对于任何托管对象,如果没有对 Timer 的引用,计时器会被垃圾回收。即使 Timer 仍处在活动状态,也会被回收。当不再需要计时器时,请使用 Dispose 方法释放计时器持有的资源。如果希望在计时器被释放时接收到信号,请使用接受 WaitHandle 的 Dispose(WaitHandle) 方法重载。计时器已被释放后,WaitHandle 便终止。 



总结: 

System.Threading.Timer 是一个简单的轻量计时器,它使用回调方法并由线程池线程提供服务。不建议将其用于 Windows 窗体,因为其回调不在用户界面线程上进行。System.Windows.Forms.Timer 是用于 Windows 窗体的更佳选择。要获取基于服务器的计时器功能,可以考虑使用 System.Timers.Timer,它可以引发事件并具有其他功能。 

在《CLR Via C#》中讲多线程时有提到这3个计时器,但作者说System.Timers.Timer是对System.Threading.Timer的报装,不推荐使用,但是在我的WEB项目中的Application_Start中我还是使用的这个而不是Threading.Timer,因为使用Threading.Timer时只执行了一次就不在执行了。 

对于计时器在B/S结构中的使用就复杂一些,一般我们把计时器放在Application_OnStart中,这样全局维护一个计时器,可以进行定期 备份 数据库,定期维护用户等操作,而且方法写作静态的,以免被垃圾回收。而不建议在一般的aspx页面中使用,因为服务器端的定时器对用户这样意义不大,完全可以使用JS代替。而且这个页面的每个请求都可能引入一个新的定时器,导致系统崩溃。另外,定时器是ASP.NET进程,IIS有关,所以对用重要的执行任务,还是建议写成服务或独立程序放在服务器上执行好了。


layui的数据表格+springmvc实现数据显示,分页功能 在做分享圈项目后台时,用的是layui提供的后端页面框架,页面挺好看的。 下载layui包:组装我们想要的页面,layui在线示例 github地址:下载示例包 看官方文档api:数据表格 实现数据显示,分页功能。 1.前端页面: 要导入layui的layui.css和layui.js <link rel="stylesheet" href="&l... 阅读详情

相关推荐

如何在 LayUI 数据表格的列元素上,鼠标悬浮,显示所有文字内容(修改源码)

文中使用的Layui版本:layui-v2.5.5 问题描述: 最近参与开发了狐小E智慧办公(https://www.hixiaoe.com)项目的管理中台模块,前端技术使用了LayUI作为前端开发的主要控件,但在使用过程中,有些功能控件未尽其能。比如遇到的问题:产品人员针对项目整体风格给出的设计,方案是项目中所有列表的展示无论每列是否完整,当鼠标悬浮到当前列时,必须出现浮动显示当前列所有内容的效果。但是原生的Layui中并未提供相关的功能实现,深表遗憾。 问题分析: 要实现鼠标悬浮显示所有内.

5370

.NET中的三种Timer的区别和用法(转)

最近正好做一个WEB中定期执行的程序,而.NET中有3个不同的定时器。所以正好研究研究。这3个定时器分别是: //1.实现按用户定义的时间间隔引发事件的计时器。此计时器最宜用于 Windows 窗体应用程序中,并且必须在窗口中使用。 System.Windows.Forms.Timer // 2.提供以指定的时间间隔执行方法的机制。无法继承此类。 System.Thread...

weixin_30480075的博客 608

Winform从入门到精通(16)——Timer(史上最全)

本文介绍Timer控件的详细用法,包含所有属性和事件,绝对史上最全!

qq_34059233的博客 4657

C# - 四种定时器详细介绍和使用方法

C#定时器

weixin_43152495的博客 1万+

WinForm中使用Timer控件实现定时功能

在WinForm开发中,Timer控件是一个常用的工具,它可以帮助我们实现一些定时的操作,例如定时更新UI、定时执行任务等。在上面的示例中,首先创建了一个Timer对象,并设置其间隔为1秒。然后,在Timer_Tick事件处理函数中,每次定时器触发时,将计数器加1,并将其值更新到Label控件的文本上。在窗体的构造函数中,初始化了Timer对象,并将Timer_Tick事件处理函数与Tick事件关联起来。根据实际需求,可以在定时器的Tick事件处理函数中编写更复杂的逻辑代码,实现各种定时相关的功能。

NoerrorCode的博客 1844

flask、layui实现前端后端数据交互,实现数据表格的添加、删除、修改、查询

前端使用layui框架、后端使用flask框架,实现数据表格的按条件查询,实现添加、删除、修改数据同步回显到页面

zhengzaifeidelushang的博客 5750

用layui表单,前端页面的样式正常显示,但是表格内无数据显示(数据库连接和获取数据无问题)——已经解决

2、要传三个参数到前端,如下图第二个红色框框所示。因为layui框架代码如果未修改,默认要传入这三个参数。解决:1、加注释 @ResponseBody ,确保返回的是json数据。注意:用layui则不能在前端使用ajax传值,否则报错!原因:后端控制台的数据格式没有设置清楚。

2301_81873206的博客 706

神联动:LSTM+卡尔曼滤波!一区大门轻松开!

近来热度飙升,成为时间序列预测和状态估计等领域的香饽饽,非常好发高区!主要在于:这两者结合,不仅能提高模型预测准确性;还能拓展应用场景,为我们的论文创新提供发挥空间,且当下还在蓝海阶段,还不算卷。具体点说:卡尔曼滤波擅长处理线性状态估计和噪声,能使LSTM更好地适应动态环境的变化,减少噪声干扰,降低预测误差。而LSTM通过捕捉长期依赖关系,擅长处理非线性时间序列,能够弥补卡尔曼滤波在这方面的不足,从而把应用场景从传统的状态估计,延伸到金融预测、工业检测、自动驾驶等任务。

2401_82426425的博客 2208

layui中一个页面显示多个表格

遇到一个页面,有近百个table表格,然后用的是layui模板引擎,整了好久,来记个笔记。 下面是写的表格模板 <script type="text/html" id="ListTable"> <!--start 数据表格 --> <div class="table_title"> <p class="code"> <span>流水号:{{d.run_id}}</span

可可爱爱的你吖的博客 7414

从零到一:PrimeTime静态时序分析入门指南

本文详细介绍了PrimeTime静态时序分析(STA)的入门指南,从基础概念到实际应用全面覆盖。内容包括时序路径分类、PrimeTime环境搭建、时序约束设置与验证、时序分析与报告解读等核心内容,帮助工程师快速掌握STA技术,解决数字芯片设计中的时序收敛问题。

weixin_28730131的博客 268

Time-Interleaved Analog-to-Digital Converters

  这篇论文提供了时间交错模数转换器的教程回顾。在解释了偏置、增益、定时和其他不匹配对变换器性能的影响后,给出了目前解决不匹配问题的方法。论文最后总结了时间交错模数转换器的现状。 1.简介   时间交错模数转换器(ADC)将多个子ADC组合成一个ADC系统,可以实现比单独的子ADC[1]更快的采样速率。历史上,时间交错adc的主要缺点是需要紧密匹配子adc[2]的特性。近年来,由于应用需要非常宽带信号的数字化、功率高效子adc的可用性以及由深亚微米互补金属氧化物硅(CMOS)技术实现的微调技术,使得时间交错

weixin_44537056的博客 6731

layui数据表格获取数据

前端html页面 思路步骤:1.请求后端的总条数 2.后端数据的格式顺序要与表头数据相同 3.table组件接受数据的格式为 table.render({ elem: '#demp' ,url: '' ,parseData: function(res){ //res 即...

MaiCy 5522

matlab 质心重合法实现点云配准【2026最新版】

质心重合法是将源点云和目标点云的质心重合,以此缩小两点云集之间的平移误差,从而为下一步粗配准提供更好的初始位置姿态。

点云侠的博客 509

layui table数据表格中数据返回成功,但页面不显示数据内容问题

layui table数据表格中数据返回成功,但页面不显示数据内容问题。 一般导致这个问题的原因是 自己设置的返回的数据格式与layui表格中的以及固定设置好的数据格式不符合,导致无法正确显示数据于页面。 需要特别注意的是,layui中数据表格table正确的数据返回前端的成功状态码 (code)必须为:0。 1)layui table数据表格对传过来的Json数据有严格的要求,一般情况下...

Jessica_gtm的博客 1万+

【华为OD机试】2024年真题C卷(python)-API集群负载统计

【华为OD机试】-API集群负载统计-【华为OD机试】-API集群负载统计:某个产品的 restful API 集合部署在服务器集群的多个节点上,近期对客户端访问日志进行了采集,需要统计各个API的访问频次,根据热点信息在服务器节点之间做负载均衡,现在需要实现热点信息统计查询功能。 restful API 是由多个层级构成,层级之间使用/连接,如 A/B/C/D 这个地址,A属于第一级,B属于第二级,C属于第三级,D属于第四级。 现在负载均衡模块需要知道给定层级上某个名字出现的频次,未出现过用0

u014481728的博客 1492

2万字大厂面经:小米嵌入式面试题及参考答案(持续更新)

BIOS (Basic Input/Output System) 是一种存储在ROM中的固件程序,它为计算机提供了最基础的硬件初始化和服务。BIOS主要存在于传统的x86架构计算机中。嵌入式系统的启动流程取决于具体的硬件平台和所采用的操作系统。复位阶段:当系统通电或复位时,CPU进入复位状态。硬件初始化:CPU和必要的硬件设备(如内存控制器)被初始化。加载引导加载程序:引导加载程序(如U-Boot)被加载到内存中。执行引导加载程序:引导加载程序开始执行,初始化更多的硬件设备,并检测存储介质。

大模型大数据攻城狮的专栏 2529

LayUi中接口传数据成功,表格不显示数据

小编这些年深知大多数初中级工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。因此我收集整理了一份《2024年Java全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!如果你需要这些资料,⬅专栏获取。

2401_85767411的博客 1599

Python爬虫教程:抓取社交媒体内容(以Facebook和Instagram为例)

为什么抓取社交媒体内容?品牌分析与监测:通过抓取品牌、产品或服务相关的社交媒体数据,可以获得公众对其的评价,识别市场趋势,制定营销策略。情感分析:分析用户在社交平台上的情感倾向,如对某事件、产品、服务的正面或负面情绪。舆情监控:通过抓取大量社交媒体内容,监测公众对热点事件的反应,发现潜在的社会问题。用户行为分析社交媒体的数据类型:帖子和内容:包括用户发布的文本、图片、视频等。用户互动用户信息:包括用户名、粉丝数、关注数等社交信息。社交媒体的反爬虫机制:API限制。

2201_76125261的博客 1338

关于layui的表格数据(前端HTML+后端SSM)——显示数据

先上代码 前端html <table class="layui-hide" id="test" lay-filter="test"></table> 前端js <script src="../layui/layui.js" charset="utf-8"></script> 前端layui layui.use('table', function(){ var table = layui.table; $=layui.jquery;

qq_35623400的博客 3565

ArcGIS JSAPI 高级教程 - 添加多个 box 立方体 - 通过顶点、索引、UV 自定义每个 box、每个面不同颜色

ArcGIS JSAPI 高级教程 - 添加多个 box 立方体 - 通过顶点、索引、UV 自定义每个 box、每个面不同颜色。

非科班Java出身GISer的博客 400

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Layui 表格显示数据

Layui 表格显示数据 让页面表格显示数据需要链接控制器 如图: 需要先声明一个方法 再用layui 里面 数据表格里的 reload 重载 方法 图中双引号里面的tabAcademe 是需要往里面加SQL里面数据的 用url 地址链接 后在控制器里 要连接数据库里的数据需要 使用 Models 就要先把Models实例化 如: 模型Models 里面的数据是从数据库SQL里面传过来的 SchoolMangeSystemEntites就是Models的name名称 通过这个名称 声明对象来接收 Mo

weixin_47282637的博客 3243

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

layui数据表格及分页显示

原本数据显示页面使用框架自带的分页显示,不是异步加载,页面需要重新加载,影响用户体验。因为原本使用的前端框架是layui,故使用layui的数据表格进行数据显示。 layui版本:2.4.5 引入layui的css和js文件,layui官网,进入官网首页可以看到下载的链接 在html中添加需要显示表格的table标签 html代码: &lt;table class="layui-tab...

Stonelalala的博客 1万+

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

layui table数据表格前端分页

下面js代码是在前端进行分页,主要是利用表格插件的parseData参数,该参数触发是在请求数据回来后,但还未显示在表中时触发的。 layui.use('table', function(){ var table = layui.table; table.render({ elem: '#gridTable' , url: contextPath + '/pages...

glgom的博客 7629

layui表格接受list_layui之数据表格--与后台交互获取数据的方法

jsp或htmljs//用户列表var tableIns = table.render({elem: '#userList',url : 'userAction_findAll.action',cellMinWidth : 95,page : true,height : "full-125",limits : [10,15,20,25],limit : 10,id : "userListTable...

weixin_32824369的博客 1941
上一篇: C# 主线程 辅助线程
下一篇: XAF之深入理解Application Model
qjpcpu
博客等级 码龄15年 59粉丝 106原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值