winform程序,调用多个timer1 画面顿卡

qq_36198178 2017-05-08 05:38:46
大家好,我又来了。其实很不好意思,因为感觉自己弄了两个多月,还是啥都不会一样。
但各种尝试后,实在没辙了,只能来这里求助了。
容我先描述下我要做的东西:
一个winform界面,主要考虑两部分:
1.车(图片)的移动。
2.实时的从数据库中读取信息(每50ms读一次,并与上一次的数据比较,若不同,则在界面上的label显示相关的内容)

所以我的想法是设置三个timer1:
timer1:控制车的移动(我用的是改变图片坐标的方法,像这样:this.pictureBox1.Left -= 10;)
timer2:从数据库中读取表1的一个id,并判断如果id与上次的不一样,则表示可以读其他表里的数据。
timer3:读取数据库中其他的表(每50ms读一次),并判断如果与上次读的值不一样,就输出到界面里。

问题是:当我加了读数据库的timer后,画面就变的顿卡,效果如下:
只有timer1的时候:(此时图片移动很流畅)



————————————分割线————————————————————
————————————分割线————————————————————
————————————分割线————————————————————
————————————分割线————————————————————


加了timer3之后:(顿卡)


我自己想过的解决办法有:
将timer3换成异步定时器,但是读数据库的时候总是出错,一会说和DataReader已关闭需要打开,一会说Datareader已打开需要关闭。我猜的原因是主线程里也有读取数据库的数据,二者是不是串了,但也不知道怎么办,最终没能解决。
我咨询老师的办法:
老师说我移动图片的思路有问题,让我用Graphics重绘+双缓冲的方法移动图片。我试着弄了下,但想不出来怎么用这种方法移动图片。

我现在是在继续想用Graphics重绘的方法如何循环移动图片,但我不知道这种方法能不能最终解决问题。
所以我想来这里求助大家,大家有什么办法吗?

...全文
1587 23 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_36198178 2017-05-10
  • 打赏
  • 举报
回复
引用 9 楼 xuzuning 的回复:
我同意你的这个观点,你并没有找到问题的原因 之前我跟踪过你的这个项目,并留有动画不凡的代码。但在其中加上另外的定时器后,对动画没有任何影响,至少肉眼是看不出来的 其实 Forms.Timer.Tick 的响应程序是在子线程中运行的,因此他不会,也不应该影响另一个 Forms.Timer.Tick 的行为
终于算是解决了 我还是用了一个异步定时器 并把数据库查询语句都给修正了下 谢了啊 版主!
qq_36198178 2017-05-10
  • 打赏
  • 举报
回复
引用 14 楼 sp1234 的回复:
50 ms 进行一次数据库查询自然是很卡。有的人以为程序中只会有这样一、两个轮询,那是因为它很少评估别人的程序。 我们稍不留神,就会被一些实习生在系统里偷偷地扔进去什么“50ms 定时器”代码。实际上一看到程序突然某天变卡了,就会赶紧去检查有没有人偷偷植入什么定时器代码。所以这时候这种 timer 代码就不仅仅是你自己“玩儿”一个小例子的问题,而是整个的程序设计的事件驱动设计知识问题,代表着某些人对于涉及到事件驱动的部分可能完全不理解、完全不去进行设计。
终于算是解决了 我还是用了一个异步定时器 并把数据库查询语句都给修正了下 谢了啊 兄弟!
qq_36198178 2017-05-10
  • 打赏
  • 举报
回复
引用 19 楼 baidu_27549073 的回复:
[quote=引用 6 楼 qq_36198178 的回复:] [quote=引用 3 楼 sp1234 的回复:] 如果确实是定时执行什么操作,那么以定时器 Timer 驱动是正常的、正规的。 但是有的人不懂事件驱动的道理,用多个 timer 来模拟事件驱动,这就往往是搞砸了系统的顺畅性能。系统中不管是属性值改变,还是数据发送或者接收(I/O),或者是用户交互操作了一下子,等等,都是事件驱动的。这个设计技术和概念,远比你这整个项目还重要。 至于说你的 timer2、timer3 应该合并的流程,其实就是类似
var x = 查询最新id();
if(x != 旧的id)
{
    旧的id = x;
    ThreadPool.QueueUserWorkItem(h => 读取第1个数据库并且处理());
    ThreadPool.QueueUserWorkItem(h => 读取第2个数据库并且处理());
    ThreadPool.QueueUserWorkItem(h => 读取第3个数据库并且处理());
}
这样地异步、多线程地触发子任务,使得子任务能够并发执行。而不要见了什么并发任务又去想到 Timer。 你在事件驱动设计方面滥用 timer。在并发子任务方面滥用 timer。这两的问题都比较严重。
兄弟 首先很感谢您的回复。 虽然自己多线程、异步、数据库主动通知程序这些没听懂,主要是脑子里没货,但是觉得很受用,而且以后肯定用得着,目前我能一下子收获到的是: 1.确实 timer2 和 timer3可以合并成一个就行,这一点是我没想到,被你提醒,有一种恍然大悟的感觉。 但我试了下,将timer2和timer3合并到一个异步定时器里面,读数据库一直报错,我设置断点调试,一直在第一个数据库查询方法里乱跳,让我很搞不懂逻辑,不知道接下来怎么办。 我将异步timer里的代码,复制到timer2里(相当于我没有用异步定时器,而是用了两个timer控件:timer1控制图片移动,timer2控制读取数据库),则可以顺利读出数据,只是顿卡现象解决不了。 一样的程序,在异步定时器里却一直报异常。 我的第一个数据库查询方法是这样的:(主程序的异步定时器里,调用了一下这个方法,还没执行完,就异常了) public static void Query_data_whole(SqlConnection conn, out int x, out int y) { int temp1 = 0; int temp2 = 0; string str_drw_id = "select * from dbo.data_record_whole where drw_id in (select max(drw_id) from dbo.data_record_whole)"; if (conn != null) { SqlCommand comm = new SqlCommand(str_drw_id, conn); SqlDataReader myreader; myreader = comm.ExecuteReader(); while (myreader.Read()) { temp1 = Convert.ToInt32(myreader["drw_id"]); temp2 = Convert.ToInt32(myreader["ts_id"]); } if (!myreader.IsClosed) { myreader.Close(); } } x = temp1; y = temp2; } 然后我加断点调试,就一直在 int temp1 = 0;和myreader = comm.ExecuteReader();来回跳,直到最后报出这样的异常: “System.InvalidOperationException”类型的异常在 System.Data.dll 中发生,但未在用户代码中进行处理 其他信息: ExecuteReader 要求已打开且可用的 Connection。连接的当前状态为打开。 2.ThreadPool.QueueUserWorkItem(h => 读取第1个数据库并且处理()); 意思是在异步定时器里也可以这样来调用方法吗? 因为我对多线程这方面还没什么认识,所以如果要解决顿卡的问题,我当前是否最要紧的就是补一下多线程这方面的知识?[/quote] 1、你这个读数据库的频率太快了。下一次定时器开始时上一次还没执行完。到后面就堆到一起了。 2、对你现在来说简单有效的办法是加长时间 3、你设计的又问题,没有读一串数据,只有最后50ms的数据是不同的。这太浪费了,每次读最后50MS的,然后让客户端判断。 4、数据量会随着时间越来越大,所以也越来越慢[/quote] 恩 谢谢!我现在用了一个异步定时器 并修改了一些查询语句 这个问题解决了!
baidu_27549073 2017-05-10
  • 打赏
  • 举报
回复
3、你设计的又问题,没有读一串数据,---》你设计的又问题,每次读全部数据
baidu_27549073 2017-05-10
  • 打赏
  • 举报
回复
引用 6 楼 qq_36198178 的回复:
[quote=引用 3 楼 sp1234 的回复:] 如果确实是定时执行什么操作,那么以定时器 Timer 驱动是正常的、正规的。 但是有的人不懂事件驱动的道理,用多个 timer 来模拟事件驱动,这就往往是搞砸了系统的顺畅性能。系统中不管是属性值改变,还是数据发送或者接收(I/O),或者是用户交互操作了一下子,等等,都是事件驱动的。这个设计技术和概念,远比你这整个项目还重要。 至于说你的 timer2、timer3 应该合并的流程,其实就是类似
var x = 查询最新id();
if(x != 旧的id)
{
    旧的id = x;
    ThreadPool.QueueUserWorkItem(h => 读取第1个数据库并且处理());
    ThreadPool.QueueUserWorkItem(h => 读取第2个数据库并且处理());
    ThreadPool.QueueUserWorkItem(h => 读取第3个数据库并且处理());
}
这样地异步、多线程地触发子任务,使得子任务能够并发执行。而不要见了什么并发任务又去想到 Timer。 你在事件驱动设计方面滥用 timer。在并发子任务方面滥用 timer。这两的问题都比较严重。
兄弟 首先很感谢您的回复。 虽然自己多线程、异步、数据库主动通知程序这些没听懂,主要是脑子里没货,但是觉得很受用,而且以后肯定用得着,目前我能一下子收获到的是: 1.确实 timer2 和 timer3可以合并成一个就行,这一点是我没想到,被你提醒,有一种恍然大悟的感觉。 但我试了下,将timer2和timer3合并到一个异步定时器里面,读数据库一直报错,我设置断点调试,一直在第一个数据库查询方法里乱跳,让我很搞不懂逻辑,不知道接下来怎么办。 我将异步timer里的代码,复制到timer2里(相当于我没有用异步定时器,而是用了两个timer控件:timer1控制图片移动,timer2控制读取数据库),则可以顺利读出数据,只是顿卡现象解决不了。 一样的程序,在异步定时器里却一直报异常。 我的第一个数据库查询方法是这样的:(主程序的异步定时器里,调用了一下这个方法,还没执行完,就异常了) public static void Query_data_whole(SqlConnection conn, out int x, out int y) { int temp1 = 0; int temp2 = 0; string str_drw_id = "select * from dbo.data_record_whole where drw_id in (select max(drw_id) from dbo.data_record_whole)"; if (conn != null) { SqlCommand comm = new SqlCommand(str_drw_id, conn); SqlDataReader myreader; myreader = comm.ExecuteReader(); while (myreader.Read()) { temp1 = Convert.ToInt32(myreader["drw_id"]); temp2 = Convert.ToInt32(myreader["ts_id"]); } if (!myreader.IsClosed) { myreader.Close(); } } x = temp1; y = temp2; } 然后我加断点调试,就一直在 int temp1 = 0;和myreader = comm.ExecuteReader();来回跳,直到最后报出这样的异常: “System.InvalidOperationException”类型的异常在 System.Data.dll 中发生,但未在用户代码中进行处理 其他信息: ExecuteReader 要求已打开且可用的 Connection。连接的当前状态为打开。 2.ThreadPool.QueueUserWorkItem(h => 读取第1个数据库并且处理()); 意思是在异步定时器里也可以这样来调用方法吗? 因为我对多线程这方面还没什么认识,所以如果要解决顿卡的问题,我当前是否最要紧的就是补一下多线程这方面的知识?[/quote] 1、你这个读数据库的频率太快了。下一次定时器开始时上一次还没执行完。到后面就堆到一起了。 2、对你现在来说简单有效的办法是加长时间 3、你设计的又问题,没有读一串数据,只有最后50ms的数据是不同的。这太浪费了,每次读最后50MS的,然后让客户端判断。 4、数据量会随着时间越来越大,所以也越来越慢
正怒月神 2017-05-09
  • 打赏
  • 举报
回复
如果你的客户端不是很多的情况下。 其实使用 SqlDependency 来使数据库主动通知你的程序比较好。 而不是使用轮训50ms这种方式。毕竟数据库的打开关闭还是很消耗资源的。 说的简单点,其实你使用一种长连接的方式,去读取数据比较实在。而不是50ms都打开关闭数据库。
  • 打赏
  • 举报
回复
50 ms 进行一次数据库查询自然是很卡。有的人以为程序中只会有这样一、两个轮询,那是因为它很少评估别人的程序。 我们稍不留神,就会被一些实习生在系统里偷偷地扔进去什么“50ms 定时器”代码。实际上一看到程序突然某天变卡了,就会赶紧去检查有没有人偷偷植入什么定时器代码。所以这时候这种 timer 代码就不仅仅是你自己“玩儿”一个小例子的问题,而是整个的程序设计的事件驱动设计知识问题,代表着某些人对于涉及到事件驱动的部分可能完全不理解、完全不去进行设计。
  • 打赏
  • 举报
回复
这个问题中,你的描述方式其实挺好,你首先给出了不读取数据库的时候“图片移动很流畅”的前提,这就说明了你这个问题首先应该去解决占用主线程来进行非 UI 操作的问题,而并不需要考虑什么双缓冲之类的。 反之,这里其实也间接说明了,不把相关的事件驱动响应流程、异步计算处理等基本设计模式学会,终究是纠结到底层去了,而应用层的设计你还是不会。
秋的红果实 2017-05-09
  • 打赏
  • 举报
回复
还有个建议,你的问题可以考虑用flash做,写少许actionscript语句就行,省事多了 flash尽管不支持数据库,但支持文件,可以满足你们的项目需求
秋的红果实 2017-05-09
  • 打赏
  • 举报
回复
你可以建立连个连接conn1和conn2==>你可以建立两个连接conn1和conn2
秋的红果实 2017-05-09
  • 打赏
  • 举报
回复
火车移动,简单方法,就用你的方式,设置双缓存 timer1放到主线程,另两个放到两个独立的线程里面 至于你说的 ”将timer3换成异步定时器,但是读数据库的时候总是出错,一会说和DataReader已关闭需要打开,一会说Datareader已打开需要关闭“ 你可以建立连个连接conn1和conn2,分别应对timer1和timer2的动作。这样就不会出现你说的情况 实时性要求如此高的应用,为什么要使用数据库?放到内存处理不是更快吗,你的数据应该是从物理传感器传进来的吧,直接放到内存处理,datatable
qq_36198178 2017-05-09
  • 打赏
  • 举报
回复
引用 12 楼 From_TaiWan 的回复:
还有个建议,你的问题可以考虑用flash做,写少许actionscript语句就行,省事多了 flash尽管不支持数据库,但支持文件,可以满足你们的项目需求
多谢兄弟建议,但一个是需要连数据库,二是我现在就像煞笔一样,一片蒙,弄了两个月了,这么简单的问题都弄不好,更别说flash、actionscript我听都没听过的东西。感觉很烦躁,像解决问题,但力又没处使
qq_36198178 2017-05-09
  • 打赏
  • 举报
回复
引用 14 楼 sp1234 的回复:
50 ms 进行一次数据库查询自然是很卡。有的人以为程序中只会有这样一、两个轮询,那是因为它很少评估别人的程序。 我们稍不留神,就会被一些实习生在系统里偷偷地扔进去什么“50ms 定时器”代码。实际上一看到程序突然某天变卡了,就会赶紧去检查有没有人偷偷植入什么定时器代码。所以这时候这种 timer 代码就不仅仅是你自己“玩儿”一个小例子的问题,而是整个的程序设计的事件驱动设计知识问题,代表着某些人对于涉及到事件驱动的部分可能完全不理解、完全不去进行设计。
今天又浪费了一天时间 ,感觉自己完全是在瞎折腾,现在的状态是一片混乱,越弄越不知道如何下手。 今天看了一些多线程、委托的介绍,但完全是囫囵吞枣,根本没能解决问题。 索性我想把自己的思路清一下,直接回归问题本身,能麻烦你再看下吗: 我现在有两个 Forms.Timer: timer1控制图片的移动,timer2控制从数据库读数据并显示在界面中。 单独只有timer1的时候,图片移动很流畅。单两个timer一起就图片移动就一顿一顿的。 这种情况下我应该从什么地方下手去解决问题?
qq_36198178 2017-05-09
  • 打赏
  • 举报
回复
引用 9 楼 xuzuning 的回复:
我同意你的这个观点,你并没有找到问题的原因 之前我跟踪过你的这个项目,并留有动画不凡的代码。但在其中加上另外的定时器后,对动画没有任何影响,至少肉眼是看不出来的 其实 Forms.Timer.Tick 的响应程序是在子线程中运行的,因此他不会,也不应该影响另一个 Forms.Timer.Tick 的行为
是的 那我换个描述 你能看下么: 我现在有两个 Forms.Timer: timer1控制图片的移动,timer2控制从数据库读数据并显示在界面中。 单独只有timer1的时候,图片移动很流畅。单两个timer一起就图片移动就一顿一顿的。 这种情况下我应该从什么地方下手去解决问题? (两个timer2的间隔时间我都调过,不能解决顿卡的问题)
xuzuning 2017-05-08
  • 打赏
  • 举报
回复
我同意你的这个观点,你并没有找到问题的原因 之前我跟踪过你的这个项目,并留有动画不凡的代码。但在其中加上另外的定时器后,对动画没有任何影响,至少肉眼是看不出来的 其实 Forms.Timer.Tick 的响应程序是在子线程中运行的,因此他不会,也不应该影响另一个 Forms.Timer.Tick 的行为
qq_36198178 2017-05-08
  • 打赏
  • 举报
回复
引用 5 楼 xuzuning 的回复:
time3 的周期是 50ms,那么你其中的数据库访问处理能保证在 50ms 内完成吗?
我换过时间,换成100ms,200ms,依旧不行。 应该还是我问题描述的可能不是太清楚,感觉自己就是这样:只能说出自己不会,但具体是怎么个不会法,却说不清楚,这个贴我都是想了一下午,才写出来的。。。。
qq_36198178 2017-05-08
  • 打赏
  • 举报
回复
引用 1 楼 u010941149 的回复:
来店代码,我研究研究啊
兄弟 多谢哈 虽然是个很low的东西 但是老师不允许的话 我不好直接在网上全部贴出来,虽然我也很想让你帮忙研究下 望理解!
qq_36198178 2017-05-08
  • 打赏
  • 举报
回复
引用 3 楼 sp1234 的回复:
如果确实是定时执行什么操作,那么以定时器 Timer 驱动是正常的、正规的。 但是有的人不懂事件驱动的道理,用多个 timer 来模拟事件驱动,这就往往是搞砸了系统的顺畅性能。系统中不管是属性值改变,还是数据发送或者接收(I/O),或者是用户交互操作了一下子,等等,都是事件驱动的。这个设计技术和概念,远比你这整个项目还重要。 至于说你的 timer2、timer3 应该合并的流程,其实就是类似
var x = 查询最新id();
if(x != 旧的id)
{
    旧的id = x;
    ThreadPool.QueueUserWorkItem(h => 读取第1个数据库并且处理());
    ThreadPool.QueueUserWorkItem(h => 读取第2个数据库并且处理());
    ThreadPool.QueueUserWorkItem(h => 读取第3个数据库并且处理());
}
这样地异步、多线程地触发子任务,使得子任务能够并发执行。而不要见了什么并发任务又去想到 Timer。 你在事件驱动设计方面滥用 timer。在并发子任务方面滥用 timer。这两的问题都比较严重。
兄弟 首先很感谢您的回复。 虽然自己多线程、异步、数据库主动通知程序这些没听懂,主要是脑子里没货,但是觉得很受用,而且以后肯定用得着,目前我能一下子收获到的是: 1.确实 timer2 和 timer3可以合并成一个就行,这一点是我没想到,被你提醒,有一种恍然大悟的感觉。 但我试了下,将timer2和timer3合并到一个异步定时器里面,读数据库一直报错,我设置断点调试,一直在第一个数据库查询方法里乱跳,让我很搞不懂逻辑,不知道接下来怎么办。 我将异步timer里的代码,复制到timer2里(相当于我没有用异步定时器,而是用了两个timer控件:timer1控制图片移动,timer2控制读取数据库),则可以顺利读出数据,只是顿卡现象解决不了。 一样的程序,在异步定时器里却一直报异常。 我的第一个数据库查询方法是这样的:(主程序的异步定时器里,调用了一下这个方法,还没执行完,就异常了) public static void Query_data_whole(SqlConnection conn, out int x, out int y) { int temp1 = 0; int temp2 = 0; string str_drw_id = "select * from dbo.data_record_whole where drw_id in (select max(drw_id) from dbo.data_record_whole)"; if (conn != null) { SqlCommand comm = new SqlCommand(str_drw_id, conn); SqlDataReader myreader; myreader = comm.ExecuteReader(); while (myreader.Read()) { temp1 = Convert.ToInt32(myreader["drw_id"]); temp2 = Convert.ToInt32(myreader["ts_id"]); } if (!myreader.IsClosed) { myreader.Close(); } } x = temp1; y = temp2; } 然后我加断点调试,就一直在 int temp1 = 0;和myreader = comm.ExecuteReader();来回跳,直到最后报出这样的异常: “System.InvalidOperationException”类型的异常在 System.Data.dll 中发生,但未在用户代码中进行处理 其他信息: ExecuteReader 要求已打开且可用的 Connection。连接的当前状态为打开。 2.ThreadPool.QueueUserWorkItem(h => 读取第1个数据库并且处理()); 意思是在异步定时器里也可以这样来调用方法吗? 因为我对多线程这方面还没什么认识,所以如果要解决顿卡的问题,我当前是否最要紧的就是补一下多线程这方面的知识?
xuzuning 2017-05-08
  • 打赏
  • 举报
回复
time3 的周期是 50ms,那么你其中的数据库访问处理能保证在 50ms 内完成吗?
sdfgrtyu 2017-05-08
  • 打赏
  • 举报
回复
引用 3 楼 sp1234 的回复:
如果确实是定时执行什么操作,那么以定时器 Timer 驱动是正常的、正规的。 但是有的人不懂事件驱动的道理,用多个 timer 来模拟事件驱动,这就往往是搞砸了系统的顺畅性能。系统中不管是属性值改变,还是数据发送或者接收(I/O),或者是用户交互操作了一下子,等等,都是事件驱动的。这个设计技术和概念,远比你这整个项目还重要。 至于说你的 timer2、timer3 应该合并的流程,其实就是类似
var x = 查询最新id();
if(x != 旧的id)
{
    旧的id = x;
    ThreadPool.QueueUserWorkItem(h => 读取第1个数据库并且处理());
    ThreadPool.QueueUserWorkItem(h => 读取第2个数据库并且处理());
    ThreadPool.QueueUserWorkItem(h => 读取第3个数据库并且处理());
}
这样地异步、多线程地触发子任务,使得子任务能够并发执行。而不要见了什么并发任务又去想到 Timer。 你在事件驱动设计方面滥用 timer。在并发子任务方面滥用 timer。这两的问题都比较严重。
加载更多回复(3)

111,093

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧