c#线程中的代码执行时间非固定,而是越来越长

时间:2021-03-08 18:11:15
        是这样的,我创建了一个线程A,A是写在一个thread类型定时器内,用来循环执行A,循环时间设置为5S,在A中有一段for循环代码,为了测试该代码每次执行过程的大致时间,我在代码前后分别加了两个累加数,测试发现刚开始很快,不到1S就执行完毕。但随着时间的流逝,执行整段循环代码的耗时越来越长,甚至超过5S。每次重新运行都是刚开始很快,然后慢慢变慢。
        因为代码里面含有对数据库的操作,每次重新运行都是刚开始很快,然后慢慢变慢。所以个人觉得应该不是数据库表中数据太多导致响应时间慢慢变长。嵌套的for循环次数也不是太多,外层12,内层16,也就12X16=192次。但是发现将其改为2X5次后,就发现耗时基本保持固定数,或者叫增长的极其缓慢。
        问题1.是什么导致耗时越来越长,每次执行不应该是差不多固定时间才对嘛?
        问题2.我同时监视了CPU和内存,内存一直保持很稳定,但CPU不稳定,基本每隔5秒,就是每次执行循环代码时,CPU都会明显上升,然后回落,我给循环代码内部加了sleep(1),还是解决不了问题。另外按理说12X16次数也不是很多。改为2X5后CPU基本保持稳定。那我应该如何做才能避免CPU占用高呢?
        求各位给出建议,下面我贴下代码:
                    以下均为A()方法中的代码
                   num1++;
                   label1.text = num1.tostring();
                    //连接数据库
                    SqlConnection con = new SqlConnection();
                    con.ConnectionString = @"Data Source =王-THINK;Initial Catalog=hw;Integrated Security=SSPI";
                    con.Open();

                    SqlCommand com = new SqlCommand();
                    com.Connection = con;
                    com.CommandType = CommandType.Text;

                    for (int i = 0; i < 12; i++)
                    {
                        for (int j = 0; j < 16; j++)
                        {
                              //下面两行代码是在th这个图片类型中创建一个矩形,用来获取该矩形的最大值,引用的第三方dll,这个DLL很成熟,可以排除耗时跟它无关。
                              MeasurementRectangle rectangle = th.Measurements.Add(new Rectangle(j * 20, i * 20, 20, 20));
                              temp[i, j] = rectangle.Max.Value;
                              //存入数据库
                              com.CommandText = "insert into [Table7_Temp] (时间,时,分,秒,毫秒,行,列,温度,标识,辐射率,摄像机号,区域号,creattime,总貌X,总貌Y,总貌H,总貌W)Values(//里面的变量就赘述了,但包含 temp[i, j] );
                              SqlDataReader dr = com.ExecuteReader();//执行SQL语句
                              dr.Close();//关闭执行
                         }
                   }
                   con.Close();//关闭数据库连接
                   num2++;
                   label2.text = num2.tostring();

13 个解决方案

#1


我创建了一个线程A,A是写在一个thread类型定时器内
你意思是在timer中又跑了一个线程嘛?

#2




引用 1 楼 hanjun0612 的回复:
我创建了一个线程A,A是写在一个thread类型定时器内
你意思是在timer中又跑了一个线程嘛?


是啊,因为我要每隔5S执行一次线程A中的代码,所以写在定时器内的

#3


引用 2 楼 qq_31382269 的回复:
Quote: 引用 1 楼 hanjun0612 的回复:

我创建了一个线程A,A是写在一个thread类型定时器内
你意思是在timer中又跑了一个线程嘛?


是啊,因为我要每隔5S执行一次线程A中的代码,所以写在定时器内的

那我觉得你可以不必跑一个线程,而是直接在定时器里调用A方法就行了。
因为timer本来就是新的线程

#4


你试试直接timer的事件直接执行方法,别跑线程试试看

#5


引用 4 楼 hanjun0612 的回复:
你试试直接timer的事件直接执行方法,别跑线程试试看


您好,试过了的,还是一样的效果,耗时会慢慢变长。

#6


引用 5 楼 qq_31382269 的回复:
Quote: 引用 4 楼 hanjun0612 的回复:

你试试直接timer的事件直接执行方法,别跑线程试试看


您好,试过了的,还是一样的效果,耗时会慢慢变长。

那你先对于每个重要步骤,如录入数据库,MeasurementRectangle rectangle = th.Measurements.Add(new Rectangle(j * 20, i * 20, 20, 20));
等等,增加一个 Stopwatch 记录日志,来观察哪些步骤增加了时间

#7


  MeasurementRectangle rectangle = th.Measurements.Add(new Rectangle(j * 20, i * 20, 20, 20));
请注销这句话,给值直接给随机,我们无法确定。剪刀法则,减去他看效果
如果减去他就好了,那么请给出这玩意的代码,我们在具体分析

#8


子线程是在主线程和其他线程的缝隙(比如等待外设)间运行的,所以他没有确定的开始运行时刻,也经常会被其他线程打断
所以,执行时间不固定是正常的!甚至后创建的线程会先于先创建的线程结束运行

#9


你的代码有改进的地方
   for (int i = 0; i < 12; i++)
                    {
                        for (int j = 0; j < 16; j++)

这两个循环里在入库,要入100多次,访问100多次数据库,
你可以把这100个数据放在一个集合里,然后调用一次入库操作,比如批量入库,只访问一次数据库,减少了开销。

#10


主要是对数据库访问的问题,以你的代码ADO是对数据库访问生成了一个线程池,线程池容量有限,开始时线程池能高效提供你要的联接资源,后期没有资源就要等待前面去施放资源,所以ADO对你的联接有个锁和放锁的过程。那么问题一:因为联接线程池资源不足,用的比放的要快,问题二,CPU在进行资源调度。解决方案,一次性把数据库中的内容加载到内存里,提高使用效率。

#11


你代码优化下,用sql里面用union all关键字 把需要入库的信息全部拼起来,然后只需要执行1次数据库操作就行了,

#12


参考如下代码

CREATE TABLE test (
  ID  char(1),
  VAL varchar(5)
);
 
INSERT INTO test
  SELECT 'A',  'TRUE ' FROM dual UNION ALL
  SELECT 'A',  'TRUE ' FROM dual UNION ALL
  SELECT 'A',  'FALSE' FROM dual UNION ALL
  SELECT 'A',  'TRUE ' FROM dual UNION ALL
  SELECT 'A',  'TRUE ' FROM dual UNION ALL
  SELECT 'A',  'TRUE ' FROM dual UNION ALL
  SELECT 'A',  'FALSE' FROM dual UNION ALL
  SELECT 'A',  'TRUE ' FROM dual UNION ALL
  SELECT 'B',  'TRUE ' FROM dual UNION ALL
  SELECT 'B',  'FALSE' FROM dual UNION ALL
  SELECT 'B',  'TRUE ' FROM dual UNION ALL
  SELECT 'B',  'TRUE ' FROM dual UNION ALL
  SELECT 'B',  'FALSE' FROM dual ;

#13


引用 6 楼 hanjun0612 的回复:
Quote: 引用 5 楼 qq_31382269 的回复:

Quote: 引用 4 楼 hanjun0612 的回复:

你试试直接timer的事件直接执行方法,别跑线程试试看


您好,试过了的,还是一样的效果,耗时会慢慢变长。

那你先对于每个重要步骤,如录入数据库,MeasurementRectangle rectangle = th.Measurements.Add(new Rectangle(j * 20, i * 20, 20, 20));
等等,增加一个 Stopwatch 记录日志,来观察哪些步骤增加了时间


您好,我按照您的方法做了,发现MeasurementRectangle rectangle = th.Measurements.Add(new Rectangle(j * 20, i * 20, 20, 20));这行代码的耗时是逐步增长的,每行代码耗时乘以192差不多等于for循环前后累加数迟滞的时间。就是这行代码的问题。所以我发现每次创建的矩形居然没有销毁或删掉,粗心大意了,于是每次创建后都将其移除,执行的时间也基本差不多是固定时间了。谢谢了!

#1


我创建了一个线程A,A是写在一个thread类型定时器内
你意思是在timer中又跑了一个线程嘛?

#2




引用 1 楼 hanjun0612 的回复:
我创建了一个线程A,A是写在一个thread类型定时器内
你意思是在timer中又跑了一个线程嘛?


是啊,因为我要每隔5S执行一次线程A中的代码,所以写在定时器内的

#3


引用 2 楼 qq_31382269 的回复:
Quote: 引用 1 楼 hanjun0612 的回复:

我创建了一个线程A,A是写在一个thread类型定时器内
你意思是在timer中又跑了一个线程嘛?


是啊,因为我要每隔5S执行一次线程A中的代码,所以写在定时器内的

那我觉得你可以不必跑一个线程,而是直接在定时器里调用A方法就行了。
因为timer本来就是新的线程

#4


你试试直接timer的事件直接执行方法,别跑线程试试看

#5


引用 4 楼 hanjun0612 的回复:
你试试直接timer的事件直接执行方法,别跑线程试试看


您好,试过了的,还是一样的效果,耗时会慢慢变长。

#6


引用 5 楼 qq_31382269 的回复:
Quote: 引用 4 楼 hanjun0612 的回复:

你试试直接timer的事件直接执行方法,别跑线程试试看


您好,试过了的,还是一样的效果,耗时会慢慢变长。

那你先对于每个重要步骤,如录入数据库,MeasurementRectangle rectangle = th.Measurements.Add(new Rectangle(j * 20, i * 20, 20, 20));
等等,增加一个 Stopwatch 记录日志,来观察哪些步骤增加了时间

#7


  MeasurementRectangle rectangle = th.Measurements.Add(new Rectangle(j * 20, i * 20, 20, 20));
请注销这句话,给值直接给随机,我们无法确定。剪刀法则,减去他看效果
如果减去他就好了,那么请给出这玩意的代码,我们在具体分析

#8


子线程是在主线程和其他线程的缝隙(比如等待外设)间运行的,所以他没有确定的开始运行时刻,也经常会被其他线程打断
所以,执行时间不固定是正常的!甚至后创建的线程会先于先创建的线程结束运行

#9


你的代码有改进的地方
   for (int i = 0; i < 12; i++)
                    {
                        for (int j = 0; j < 16; j++)

这两个循环里在入库,要入100多次,访问100多次数据库,
你可以把这100个数据放在一个集合里,然后调用一次入库操作,比如批量入库,只访问一次数据库,减少了开销。

#10


主要是对数据库访问的问题,以你的代码ADO是对数据库访问生成了一个线程池,线程池容量有限,开始时线程池能高效提供你要的联接资源,后期没有资源就要等待前面去施放资源,所以ADO对你的联接有个锁和放锁的过程。那么问题一:因为联接线程池资源不足,用的比放的要快,问题二,CPU在进行资源调度。解决方案,一次性把数据库中的内容加载到内存里,提高使用效率。

#11


你代码优化下,用sql里面用union all关键字 把需要入库的信息全部拼起来,然后只需要执行1次数据库操作就行了,

#12


参考如下代码

CREATE TABLE test (
  ID  char(1),
  VAL varchar(5)
);
 
INSERT INTO test
  SELECT 'A',  'TRUE ' FROM dual UNION ALL
  SELECT 'A',  'TRUE ' FROM dual UNION ALL
  SELECT 'A',  'FALSE' FROM dual UNION ALL
  SELECT 'A',  'TRUE ' FROM dual UNION ALL
  SELECT 'A',  'TRUE ' FROM dual UNION ALL
  SELECT 'A',  'TRUE ' FROM dual UNION ALL
  SELECT 'A',  'FALSE' FROM dual UNION ALL
  SELECT 'A',  'TRUE ' FROM dual UNION ALL
  SELECT 'B',  'TRUE ' FROM dual UNION ALL
  SELECT 'B',  'FALSE' FROM dual UNION ALL
  SELECT 'B',  'TRUE ' FROM dual UNION ALL
  SELECT 'B',  'TRUE ' FROM dual UNION ALL
  SELECT 'B',  'FALSE' FROM dual ;

#13


引用 6 楼 hanjun0612 的回复:
Quote: 引用 5 楼 qq_31382269 的回复:

Quote: 引用 4 楼 hanjun0612 的回复:

你试试直接timer的事件直接执行方法,别跑线程试试看


您好,试过了的,还是一样的效果,耗时会慢慢变长。

那你先对于每个重要步骤,如录入数据库,MeasurementRectangle rectangle = th.Measurements.Add(new Rectangle(j * 20, i * 20, 20, 20));
等等,增加一个 Stopwatch 记录日志,来观察哪些步骤增加了时间


您好,我按照您的方法做了,发现MeasurementRectangle rectangle = th.Measurements.Add(new Rectangle(j * 20, i * 20, 20, 20));这行代码的耗时是逐步增长的,每行代码耗时乘以192差不多等于for循环前后累加数迟滞的时间。就是这行代码的问题。所以我发现每次创建的矩形居然没有销毁或删掉,粗心大意了,于是每次创建后都将其移除,执行的时间也基本差不多是固定时间了。谢谢了!