注册 登录
编程论坛 VB6论坛

关于VB对于系统资源的使用

renxiaoyao36 发布于 2016-05-24 18:26, 5956 次点击
近日写了一个程序,这个程序里面有大量的计算,计算量远超我之前的程序。运行的时候发现一个奇怪的现象:即使我的程序已经卡爆了,但是任务管理器里CPU使用率不超过15%
仔细看发现,程序开始运算时,有一个核的CPU使用率飙升到75%左右,但是其他CPU内核无反应。关闭程序后,该核立刻恢复到3%-5%。
在此我想请教一下各位,VB的程序是不是默认只分配一个CPU的内核呢?如果是,如何让程序可以使用多核呢?


在网上查找的资料都是关于设定程序在哪个CPU核心上运行的,没有提到如何让程序使用多个CPU核心,因此只好求助于各位了

[此贴子已经被作者于2016-5-24 18:29编辑过]

17 回复
#2
xiangyue05102016-05-24 19:00
这个没有研究过,但是确实有可能对多核支持很差,可以考虑用Matlab等编程计算,VB调用即可
#3
ZHRXJR2016-05-24 19:17
VB60是早期产品,那个时期CPU可能还没有多核产品,因此估计只能支持单核运行,不过没有研究过,VB2008以上产品是否可以支持多核。
#4
风吹过b2016-05-24 19:37
VB6 ,是天生的单线程,所以有运算都是在一个线程中完成。
也许你在任务管理器中看到 VB6 写的程序用了3个,甚至6个线程,那些线程是控件带的线程,不是VB6所能操作。

因为VB6写的程序天生是单线程,所以运算负荷重时,只有一个核会满载,也就是说如果是 4核CPU,CPU占用率永远不会超过 25%。
如果你的计算可以分解成几个部分,那可以去使用多线程,网上已有稳定多线程的方法了。
详情见:VB6多线程技术超详细示例(纯API) by秋枫萧萧(百度ID:hhyjq007)
尊重版权,这里就不上传了。

注意:VB6自带的控件及变量统统是 线程非安全 ,一定要小心,否则程序崩了找不到原因的。



[此贴子已经被作者于2016-5-24 19:45编辑过]

#5
xiangyue05102016-05-24 20:07
回复 4楼 风吹过b
呢。我用的时候还真没有注意过
#6
hjxlj2016-05-24 21:14
如果你的程序是单线程的,再多的核又有什么用?
#7
renxiaoyao362016-05-25 18:23
好吧,谢谢各位的帮助,我上网搜索一下,也谢谢风版给我的帮助。

[此贴子已经被作者于2016-5-25 21:12编辑过]

#8
renxiaoyao362016-05-25 21:16
我想了一下,决定吧我现在程序的源代码发上来(以前没接触过多线程,看网上资料一脸懵逼,决定从代码本身出发,以降低资源消耗量的方式来达成目标)
我这个程序是一个小游戏,屏幕上出现300-1000的点(视难度而定),这些点会朝你所控制的大点袭来,你要躲避他们

这一段是每个点的移动算法,请各位大大帮忙改善一下,谢谢!
代码处于计时器当中,计时器的Inyerval值为50
程序代码:
Private Sub Timer1_Timer()
For i = 0 To JValue 'JValue为当前点的数量,所有点都是一个控件数组里的
If Abs(Shape1.Top - Shape(i).Top) < 100 And Abs(Shape1.Left - Shape(i).Left) < 100 Then
Open App.Path & "\高分榜\" & Replace(Replace(Replace(Replace(Speed, "1000", "VeryDifficult.sav"), "300", "Middle.sav"), "600", "Difficult.sav"), "100", "Easy.sav") For Input As #1
Input #1, a
Close #1
If a > Time Then
MsgBox "你死了!游戏结束!未破纪录。分数:" & CStr(Time): Debug.Print i: Timer1.Enabled = False: Unload Form2: Form1.Show: Exit Sub
Else
Open App.Path & "\高分榜\" & Replace(Replace(Replace(Replace(Speed, "1000", "VeryDifficult.sav"), "300", "Middle.sav"), "600", "Difficult.sav"), "100", "Easy.sav") For Output As #1 '输出分数,REPLACE函数负责模式检测
Print #1, Time
Close #1
MsgBox "你死了!游戏结束!你的分数是最高纪录!分数:" & CStr(Time): Debug.Print i: Timer1.Enabled = False: Unload Form2: Form1.Show: Exit Sub
End If
End If
Movement = Abs(Shape1.Left - Shape(i).Left) / Abs(Shape1.Top - Shape(i).Top) '计算移动比例
Debug.Print Movement
If Shape1.Left > Shape(i).Left Then
  Shape(i).Left = Shape(i).Left + 20
ElseIf Shape1.Left < Shape(i).Left Then
  Shape(i).Left = Shape(i).Left - 20
End If
On Error Resume Next
If Movement = 0 Then Movement = 1
If Shape1.Top > Shape(i).Top Then
  Shape(i).Top = Shape(i).Top + 20 / Movement
ElseIf Shape1.Top < Shape(i).Top Then
  Shape(i).Top = Shape(i).Top - 20 / Movement
End If

Next i
End Sub

在100到150点的时候并不卡顿,但是到200点以上明显卡顿,当1000点的时候已经慢到极致了。
各位能帮我改善一下么,谢谢啦

[此贴子已经被作者于2016-5-25 21:17编辑过]

#9
风吹过b2016-05-26 17:03
你这段代码需要优化。
首先,坐标不要直接从属性里取,而是定义一个数组,然后操作数组。
操作属性是很慢的操作。
其次,动画,不要操作控件来生成,而应该自己画图。操作控件是非常慢的操作。
动画不闪的话,可以使用 二次缓冲来实现。

你说一下你的程序流程吧。
点是怎么移动的?
按大点当前位置的坐标,每次移动多少位置?速度是随机还是固定?
还是按随仙方向,固定速度或随机速度移动。


#10
renxiaoyao362016-05-26 18:54
回复 9楼 风吹过b
速度固定,这在代码里可以看出
每次固定横坐标+10,纵坐标根据移动比例计算,移动比例在代码中有计算公式
根据移动计算方式,小的点会沿直线向大点移动过去

绘图对于程序的影响可以忽略不计,因为我另外一段代码没发上来,发上来想必你就明白了。
程序代码:
Private Sub Form_Load()
Form1.Height = Screen.Height: Form1.Width = Screen.Width
If Difficulty = 1 Then
Speed = 100: Me.Caption = Me.Caption & "简单"
ElseIf Difficulty = 2 Then
Speed = 300: Me.Caption = Me.Caption & "普通"
ElseIf Difficulty = 3 Then
Speed = 600: Me.Caption = Me.Caption & "困难"
ElseIf Difficulty = 4 Then
Speed = 1000: Me.Caption = Me.Caption & "爆炸难度"
End If
Timer1.Interval = 10
MouseX = Screen.Width / 2
MouseY = Screen.Height
Dim i As Integer
For i = 1 To Speed Step 1 '循环加载部件
sss:
On Error Resume Next
Load Shape(i): Shape(i).Left = 40000 * Rnd: Shape(i).Top = 20000 * Rnd: Shape(i).FillColor = Shape(0).FillColor: Shape(i).BorderColor = Shape(0).BorderColor: Shape(i).Height = 135: Shape(i).Width = 135: Shape(i).Visible = True: Shape(i).Shape = 3
If Shape(i).Left < MouseX + 1000 And Shape(i).Left > MouseX - 1000 Then GoTo sss
If Shape(i).Top < MouseY + 1000 And Shape(i).Top > MouseY - 1000 Then GoTo sss '防止生成在鼠标附近
Next i
Me.WindowState = 2
SetCursorPos ScaleX((Screen.Width / 2), 1, 3), ScaleY((Screen.Height / 2), 1, 3) '移动鼠标位置  
Debug.Print Screen.Width
Debug.Print Screen.Width / 2
Timer1.Enabled = True
JValue = Speed
Time = -1
End Sub
Private Sub Timer2_Timer()
For i = JValue To JValue + 30
sss:
On Error Resume Next
Load Shape(i): Shape(i).Left = 40000 * Rnd: Shape(i).Top = 20000 * Rnd: Shape(i).FillColor = Shape(0).FillColor: Shape(i).BorderColor = Shape(0).BorderColor: Shape(i).Height = 135: Shape(i).Width = 135: Shape(i).Visible = True: Shape(i).Shape = 3
If Shape(i).Left < MouseX + 1000 And Shape(i).Left > MouseX - 1000 Then GoTo sss
If Shape(i).Top < MouseY + 1000 And Shape(i).Top > MouseY - 1000 Then GoTo sss '防止生成在鼠标附近
Next i
JValue = JValue + 30
End Sub

Timer2的Interval为5000
这段代码主要是在加载窗体时加载小的点,同时移动鼠标坐标,控制大的点的代码如下:
程序代码:
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
MouseX = x
MouseY = y
Shape1.Left = x - 100
Shape1.Top = y - 100
End Sub


坐标不要直接从属性里取,而是定义一个数组,然后操作数组。

意思是不是在加载点的时候将点的初始坐标写入数组,然后每次都调用数组?
这样的话每次移动小点的步骤将会多很多啊,个人认为不能解决代码速度的问题,反而可能更加慢

还是感谢风版的帮助,如果有空的话再助小弟一臂之力如何?我也会仔细思考如何优化代码的。

[此贴子已经被作者于2016-5-26 18:56编辑过]

#11
风吹过b2016-05-26 21:29
只有本站会员才能查看附件,请 登录


你参考参考吧。
这个程序里采取的是二次缓冲绘图,所以不会闪。我没加计分啥情况的。
还有碰撞检测还有点问题,可能是因为绘图就没绘好的原因。
感觉绘图半径的线的大小需要再仔细琢磨一下。



[此贴子已经被作者于2016-5-26 21:32编辑过]

#12
renxiaoyao362016-05-27 17:42
回复 11楼 风吹过b
风版事实上不需要那么麻烦再替我写个工程的,我只是需要一点建议,我可不是什么伸手党,您这样反而会让我过意不去的……真是麻烦了……
另外,您的工程我看了一下,借鉴作用有,但是不算很大。您的工程的算法有些不大一样,同时也没有解决我最重要的问题:程序卡顿问题
我把我的工程源文件发上来吧,您如果不嫌麻烦的话看一下吧,测试一下我的工程,看一下程序结果,然后在此基础上提一点加快程序运行速度的建议吧

我不是对您的方案否定,只是您的方案不适合我罢了……

以下是源文件
只有本站会员才能查看附件,请 登录
#13
风吹过b2016-05-27 19:37
看了你的代码,
其他都没啥问题,关键就是在 显示部分。
使用控件来进行动画,肯定慢的。你的代码,说实在的,我无从下手改造。

还是建议你按我的显示方案改造,我的代码里,我是偷懒只用一个二维数组保存,按规范应该使用一个结构体。
这个结构的定义包括以下内容:
X
Y
移动速度
半径
生存周期
点颜色

如果每个点不一样的大,移动速度不一样
那么后面这4个属性都可以定义。然后绘图时使用上,以达到不同的点不同的大小和速度。


#14
wmf20142016-05-27 21:11
1、注销掉Debug.Print Movement语句,print很耗时的。
2、在next i语句前加句doevents,这样至少移动空心球不会卡顿。
3、再scalemode为twip的情况下,移动的距离最好是15的倍数,这正好是屏幕上的一个点,你移动的是20,则会在转换为屏幕的点坐标时产生小数,导致移动不均匀。

[此贴子已经被作者于2016-5-27 21:22编辑过]

#15
renxiaoyao362016-05-28 07:52
谢谢,我立刻去试试看
#16
renxiaoyao362016-05-28 08:05
14L的方案测试过了,注销Debug语句后在编译环境中速度略微快了一点,但是依然会在150个点以上时卡顿
Next i语句前加了Doevents,解决了大的点的闪烁问题
移动距离更换为15后,基本没有影响,个人认为是因为我有一句代码已经注定了不可能让移动距离为整数:
程序代码:
If Movement = 0 Then Movement = 1
If Shape1.Top > Shape(i).Top Then
  Shape(i).Top = Shape(i).Top + 15 / Movement
ElseIf Shape1.Top < Shape(i).Top Then
  Shape(i).Top = Shape(i).Top - 15 / Movement


我最近思考得出了一点结果,我觉得导致程序速度不佳的一个原因很可能是在Timer1里面:
我使用了For循环,而For循环是在一个Timer里的,这就导致随着点的增多,Timer的运行速度会越来越慢。
个人解决方案:编写一个算法,判定当点的数量大于X时,启用某个Timer,就是每个Timer仅仅处理50个点的移动。
但是算法还没想出来,正在努力思考中,先把我的想法发上来,如果大家发现我的想法有误也可以即使告诉我,让我不用在岔路上越走越远。
#17
wmf20142016-05-28 09:27
回复 16楼 renxiaoyao36
用vb的控件或普通作图语句是完成不了多元素作图的,因为在一定的时间片断内完成不了全屏刷图,卡顿是肯定的。实际上即使用api的bitblt函数刷我现在的这个1680*1050的屏幕也只有每秒4帧左右的刷屏速率,实际游戏处理多元素图形时,同样面临刷新速率跟不上的问题,一般的解决办法是采取分层处理手段或仿真手段,具体做法是游戏数据运算实际是在数组矩阵中完成,往屏幕上显示则是实时刷敌我关系最近的几个元素,其他元素则刷的过来就刷,刷不过来就丢弃,反正不影响实际战斗结果。
#18
renxiaoyao362016-05-28 17:32
谢谢大家的帮助,我先把帖子结了,到时候另外启一个帖子继续讨论吧
1