我已经开了100个线程,为什么效率很低? ( 积分: 120 )

  • 主题发起人 主题发起人 牛头12236
  • 开始时间 开始时间

牛头12236

Unregistered / Unconfirmed
GUEST, unregistred user!
最近公司要求我开发一个项目,服务器端需要模拟运行一百台控制站,这些控制站编号从1到100,每隔一个周期(比如500MS)按照一定的算法更新每一台控制站中的数据,实时性要求很高,并且响应客户端请求要快。
控制站数据定义如下:
DataArray_A: array[0..100 - 1] of array[0..450000 - 1] of Integer;
DataArray_B: array[0..100 - 1] of array[0..6000 - 1] of Integer;
DataArray_C: array[0..100 - 1] of array[0..60 - 1] of Integer;
另外还有提供给这些控制站共享的数据定义如下:
Data_Share_A: array[0..100 * 2000] of Integer;
Data_Share_B: array[0..100 * 2000] of Integer;
  客户端通过COM+技术与服务器端通信,并与这一百个控制站其中一个进行通信。
我是这样做的:在服务器端运行时创建了一百个线程,这些线程只负责每隔一定的周期更新对应的控制站的数据,更新数据的算法是用脚本写的,也就是说每个线程每个周期时间内负责调用一次脚本控件的执行方法,并且我并没有加入书上说的线程同步技术。
  可是出现问题了,第一个是控制站数据无法实时地刷新,单单是更新内部数据就花了三四百毫秒,可是周期最快可以设置成500毫秒;还有一个是客户端访问一段时间后会异常结束,这都是大问题啊,请大虾们帮帮我。
 
最近公司要求我开发一个项目,服务器端需要模拟运行一百台控制站,这些控制站编号从1到100,每隔一个周期(比如500MS)按照一定的算法更新每一台控制站中的数据,实时性要求很高,并且响应客户端请求要快。
控制站数据定义如下:
DataArray_A: array[0..100 - 1] of array[0..450000 - 1] of Integer;
DataArray_B: array[0..100 - 1] of array[0..6000 - 1] of Integer;
DataArray_C: array[0..100 - 1] of array[0..60 - 1] of Integer;
另外还有提供给这些控制站共享的数据定义如下:
Data_Share_A: array[0..100 * 2000] of Integer;
Data_Share_B: array[0..100 * 2000] of Integer;
  客户端通过COM+技术与服务器端通信,并与这一百个控制站其中一个进行通信。
我是这样做的:在服务器端运行时创建了一百个线程,这些线程只负责每隔一定的周期更新对应的控制站的数据,更新数据的算法是用脚本写的,也就是说每个线程每个周期时间内负责调用一次脚本控件的执行方法,并且我并没有加入书上说的线程同步技术。
  可是出现问题了,第一个是控制站数据无法实时地刷新,单单是更新内部数据就花了三四百毫秒,可是周期最快可以设置成500毫秒;还有一个是客户端访问一段时间后会异常结束,这都是大问题啊,请大虾们帮帮我。
 
是脚本执行速度太慢了吧。
 
有必要这么多线程嘛!估计时间都花在线程切换上了
 
這個應該用綫程池來設計你的程序吧
難道100個綫程同時並發?
 
你开10000个,效率更低,只有一个CPU嘛
要想速度快,还是直接用Socket 吧
 
像这种任务,开这么多线程可不是最好的解决方法。
你不能够全部使用线程来避免自己的调度的责任
 
再加一个CPU吧!
 
to delphibbs_Lee:
 我有测试过当每个周期执行时间在10MS以下,执行效率是还可以的(即可以保证数据实
时地刷新),脚本执行几乎是整个系统的瓶颈,我有跟上司提过,由于改动过大且违反了设
计的初衷。
To tseug, xiaolinj79, zjan521:
对,如果要保证数据实时刷新,估计这100个线程要并发执行。
To lich, dcs_dcs, 赛特:
  这个问题我也有跟上司提过,可惜他对多线程一窍不通,怎么讲都不听,为此我们还闹过不少矛盾呢。还是客户有钱,买了台4个CPU、2G内存的服务器。呵呵,开100个线程在这台机器上只花40%左右的CPU使用率。
 
DataArray_A: array[0..100 - 1] of array[0..450000 - 1] of Integer
这个数组会占用内存:
100*450000*4/1024/1024 ~= 175M!!!
 
to dreamisx:
这没关系啊,需求是这样的,没办法。客户有钱,他的机器有2G的内存。呵呵。
 
线程太多,执行速度反而下降,
cpu用了40%己可怕了,线程的切换,很要资源的。
 用脚本肯定低效。
而且用COM+这么高层的东西,来做实时性高的需求,不太合理吧。
最好用socket完成端口或EventSelect来实现多路复用
 多线程访问共享资源,不加锁,结果是不可预测的。一量涉及指针操作,非法操作是常 出来的。
 
to djh_djh:
  djh_djh兄好眼力!
 >> 线程太多,执行速度反而下降, cpu用了40%己可怕了,线程的切换,很要资源的。
 我也感觉这样效率太低,苦于一直找不到解决问题的方法,不知djh_djh兄有何良策?
>> 用脚本肯定低效。
可以说脚本的执行在这里绝对是整体的性能瓶颈,但是公司考虑到若不这样做,不但代码改动量很大,而且违反了当时设计程序的初衷,这真是让我苦恼不已的地方。
  >> 最好用socket完成端口或EventSelect来实现多路复用
这两种技术我从未接触过,djh_djh兄可否细说?
>> 多线程访问共享资源,不加锁,结果是不可预测的。一量涉及指针操作,非法操作是常 出来的。
客户经常反映软件在运行一段时间后,会“自动”关闭。看来这段时间要把这个问题解决一下了。
  
 
  不好意思,我可能没有把问题说清楚:
  我们熟知的 SQL Server 是历史数据库,若不是人为地去改动库中的数据,一般情况下这些数据是不会改变的。而控制站刚好相反,它需要在固定的周期内按照一定的算法来更新它内部的数据,要求更新操作能够及时地完成,而Windows是抢占式操作系统,实时性没什么保证,所以,这是项目的第一个难点----怎样使程序每隔一个周期(比如500MS)来更新控制站内部数据,原先我是这样做的:
procedure TThread1.Execute;
var
BT, ET: DWORD;
msg: TMsg;
begin
BT := timeGetTime;
while Truedo
begin
if PeekMessage(msg, 0, 0, 0, PM_REMOVE) then
if msg.message = WM_QUIT
 
  按错键了,接上一贴:
if msg.message = WM_QUIT then
break;
// 在这里执行控制站内部数据更新
do
SomeThing;
ET := timeGetTime;
if ET - BT > 500 then
// 若操作所花的时间未满一个周期,则转让控制权
Sleep(500 - ET - BT);
end;
end;
 
关于实时性,我觉得你走进了误区,按你所述500ms的时间,windows完全可以保证
所谓实时,只要在系统要求的响应时间内能保证响应就可以了,这个指标有可能是
微秒级别,也有可能是秒级别的,只要满足要求都可以算作实时
针对你特定的问题,你可以建一个队列用于缓存数据,然后3,5个线程来读取队列
根据数据进行处理脚本,估计效率能高点
 
上面的代码中没有包括处理客户端请求的代码。你们知道,这也许是在Windows下的多线程应用中最蠢的办法了。
  上面介绍了模拟一台控制站的原理。我们的软件要求最多允许模拟一百台控制站,我们可以想像一下,当软件做了之后,在极端的情况下,每一台控制站响应一百个客户端,而这一百个客户端可能同时以50MS一个周期的速度来与控制站通信并读取数据。这正是让我头疼的地方,当然,实际应用中不可能会出现这种情况,10000个客户端,这是多么可怕的数字啊。这是项目的第二个难点----响应客户端请求要快。
 
to tseug:
>> 建一个队列用于缓存数据,然后3,5个线程来读取队列根据数据进行处理脚本
不知tseug兄所指是什么意思,能否再详细一些?
 
我觉得这样的需求还是用 完成端口+线程池 来实现比较高效,可以参见一下《WINDOWS网络编程技术》这本书的第8章以及在 http://www.codeproject.com/ 中搜IOCP相关的代码看看~
 

Similar threads

回复
0
查看
848
不得闲
S
回复
0
查看
835
SUNSTONE的Delphi笔记
S
S
回复
0
查看
765
SUNSTONE的Delphi笔记
S
后退
顶部