ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: Moneky

[分享] 分享一些关于VBA代码优化提速的资料

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2009-12-18 16:38 | 显示全部楼层
本帖已被收录到知识树中,索引项:数据类型和基本语句
原帖由 Moneky 于 2009-12-10 12:05 发表

在这段代码中是不能省略,主要是因为逻辑运算符的优先级低于算术运算符。前面帖子中说的可获可以省略是特指那里所举的例子的。


你说的多重判断是这样么?

Private Sub test()
Dim a As Long , b As Long  ...

我所说的多重判断是指IF嵌套。如下例,套在百万次的循环里,速度很慢。不知道能这些代码能否优化。

            If bHappy(i) > 0 Then
                WinningCount = WinningCount + 1
                If FailureCount > 0 Then                              
                    barrFailure(FailureCount) = barrFailure(FailureCount) + 1   
                    FailureCount = 0
                End If
            Else
                FailureCount = FailureCount + 1
                If WinningCount > 0 Then                              
                    barrWinning(WinningCount) = barrWinning(WinningCount) + 1     
                    WinningCount = 0
                End If
            End If
        Next

TA的精华主题

TA的得分主题

 楼主| 发表于 2009-12-18 20:09 | 显示全部楼层
原帖由 老伙计2008 于 2009-12-18 16:38 发表

我所说的多重判断是指IF嵌套。如下例,套在百万次的循环里,速度很慢。不知道能这些代码能否优化。

            If bHappy(i) > 0 Then
                WinningCount = WinningCount + 1
                If ...

用你的代码片段写了个测试程序
  1. Sub test()
  2.     Dim bHappy(1000000) As Long
  3.     Dim barrFailure(1000000) As Long
  4.     Dim barrWinning(1000000) As Long
  5.     Dim WinningCount As Long, FailureCount As Long, i As Long
  6.     Randomize
  7.     For i = 0 To 1000000
  8.         bHappy(i) = CLng(Rnd * 1000000) - CLng(Rnd * 1000000)
  9.     Next
  10.     Dim t As Single
  11.     t = Timer
  12.     For i = 0 To 1000000
  13.         WinningCount = WinningCount - (bHappy(i) > 0)
  14.         barrFailure(FailureCount) = barrFailure(FailureCount) - (bHappy(i) > 0 And FailureCount > 0)
  15.         FailureCount = IIf(bHappy(i) > 0 And FailureCount > 0, 0, FailureCount)
  16.         FailureCount = FailureCount - (bHappy(i) <= 0)
  17.         barrWinning(WinningCount) = barrWinning(WinningCount) - (bHappy(i) <= 0 And WinningCount > 0)
  18.         WinningCount = IIf(bHappy(i) <= 0 And WinningCount > 0, 0, barrWinning(WinningCount))
  19.     Next
  20.     t = Timer - t
  21.     MsgBox CStr(t)
  22. End Sub
  23. Sub test2()
  24.     Dim bHappy(1000000) As Long
  25.     Dim barrFailure(1000000) As Long
  26.     Dim barrWinning(1000000) As Long
  27.     Dim WinningCount As Long, FailureCount As Long, i As Long
  28.     Randomize
  29.     For i = 0 To 1000000
  30.         bHappy(i) = CLng(Rnd * 1000000) - CLng(Rnd * 1000000)
  31.     Next
  32.     Dim t As Single
  33.     t = Timer
  34.     For i = 0 To 1000000
  35.         If bHappy(i) > 0 Then
  36.             WinningCount = WinningCount + 1
  37.             If FailureCount > 0 Then
  38.                 barrFailure(FailureCount) = barrFailure(FailureCount) + 1
  39.                 FailureCount = 0
  40.             End If
  41.         Else
  42.             FailureCount = FailureCount + 1
  43.             If WinningCount > 0 Then
  44.                 barrWinning(WinningCount) = barrWinning(WinningCount) + 1
  45.                 WinningCount = 0
  46.             End If
  47.         End If
  48.     Next
  49.     t = Timer - t
  50.     MsgBox CStr(t)
  51. End Sub
复制代码
test2明显快于test,主要是因为test2中判断的参数少很多,而test中要判断很多次,效率自然就低了。而且test中的代码晦涩难懂,所以这种情况下,应该不适合将代码写成test那种模样

TA的精华主题

TA的得分主题

发表于 2009-12-18 21:13 | 显示全部楼层
楼主辛苦了,谢谢!让我长了不少见识

TA的精华主题

TA的得分主题

发表于 2009-12-19 01:05 | 显示全部楼层
楼主如果有时间帮我看一下这个帖子。这个帖子是与我在79楼的的回复相关的。谢谢!
同样循环1000万次,速度为什么不一样

TA的精华主题

TA的得分主题

发表于 2009-12-19 06:35 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
谢谢楼主分享

TA的精华主题

TA的得分主题

发表于 2009-12-19 20:06 | 显示全部楼层
学习了好久,有很多东西还是理解不透,不知道一下代码能否进行优化。先谢了!
说明:所有变量均为Byte型
  1. If X1 = Y1 Or X1 = Y2 Or X1 = Y3 Or X1 = Y4 Or X1 = Y5 Or X1 = Y6 _
  2.                 Or X2 = Y1 Or X2 = Y2 Or X2 = Y3 Or X2 = Y4 Or X2 = Y5 Or X2 = Y6 _
  3.                 Or X3 = Y1 Or X3 = Y2 Or X3 = Y3 Or X3 = Y4 Or X3 = Y5 Or X3 = Y6 _
  4.                 Or X4 = Y1 Or X4 = Y2 Or X4 = Y3 Or X4 = Y4 Or X4 = Y5 Or X4 = Y6 _
  5.                 Or X5 = Y1 Or X5 = Y2 Or X5 = Y3 Or X5 = Y4 Or X5 = Y5 Or X5 = Y6 _
  6.                 Or X6 = Y1 Or X6 = Y2 Or X6 = Y3 Or X6 = Y4 Or X6 = Y5 Or X6 = Y6 Then
复制代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2009-12-19 23:58 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
先前的回复不正确,删除之

[ 本帖最后由 Moneky 于 2009-12-20 00:02 编辑 ]

TA的精华主题

TA的得分主题

 楼主| 发表于 2009-12-20 00:20 | 显示全部楼层
原帖由 老伙计2008 于 2009-12-19 20:06 发表
学习了好久,有很多东西还是理解不透,不知道一下代码能否进行优化。先谢了!
说明:所有变量均为Byte型If X1 = Y1 Or X1 = Y2 Or X1 = Y3 Or X1 = Y4 Or X1 = Y5 Or X1 = Y6 _
                Or X2 = Y1 Or X2  ...


可以这样写(test2):
  1. Sub test1()
  2.     Dim x1 As Byte, x2 As Byte, x3 As Byte, x4 As Byte, x5 As Byte, x6 As Byte
  3.     Dim y1 As Byte, y2 As Byte, y3 As Byte, y4 As Byte, y5 As Byte, y6 As Byte
  4.     x1 = 0:     y1 = 0
  5.     x2 = 0:     y2 = 0
  6.     x3 = 0:     y3 = 0
  7.     x4 = 0:     y4 = 0
  8.     x5 = 0:     y5 = 0
  9.     x6 = 0:     y6 = 0
  10.     Dim i As Long
  11.     Dim j As Long
  12.     Dim t As Single
  13.     i = 0: j = 0
  14.     t = Timer
  15.     '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  16.     For j = 1 To 1000000
  17.         If x1 = y1 Or x1 = y2 Or x1 = y3 Or x1 = y4 Or x1 = y5 Or x1 = y6 _
  18.             Or x2 = y1 Or x2 = y2 Or x2 = y3 Or x2 = y4 Or x2 = y5 Or x2 = y6 _
  19.             Or x3 = y1 Or x3 = y2 Or x3 = y3 Or x3 = y4 Or x3 = y5 Or x3 = y6 _
  20.             Or x4 = y1 Or x4 = y2 Or x4 = y3 Or x4 = y4 Or x4 = y5 Or x4 = y6 _
  21.             Or x5 = y1 Or x5 = y2 Or x5 = y3 Or x5 = y4 Or x5 = y5 Or x5 = y6 _
  22.             Or x6 = y1 Or x6 = y2 Or x6 = y3 Or x6 = y4 Or x6 = y5 Or x6 = y6 Then i = i + 1
  23.     Next
  24.     '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  25.     t = Timer - t
  26.     MsgBox CStr(t) & "   i=" & CStr(i)
  27. End Sub
  28. '-----------------------------------------------------------------------------------------------------------
  29. Sub test2()
  30.     Dim x1 As Byte, x2 As Byte, x3 As Byte, x4 As Byte, x5 As Byte, x6 As Byte
  31.     Dim y1 As Byte, y2 As Byte, y3 As Byte, y4 As Byte, y5 As Byte, y6 As Byte
  32.     x1 = 0:     y1 = 0
  33.     x2 = 0:     y2 = 0
  34.     x3 = 0:     y3 = 0
  35.     x4 = 0:     y4 = 0
  36.     x5 = 0:     y5 = 0
  37.     x6 = 0:     y6 = 0
  38.     Dim i As Long
  39.     Dim j As Long
  40.     Dim t As Single, ck As Boolean
  41.     i = 0: j = 0
  42.     t = Timer
  43.     '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  44.     For j = 1 To 1000000
  45.         ck = False
  46.        '下面的代码和test1不等价,是错误程序
  47.         If x1 = y1 Then
  48.             ck = True
  49.         ElseIf x2 = y2 Then
  50.             ck = True
  51.         ElseIf x3 = y3 Then
  52.             ck = True
  53.         ElseIf x4 = y4 Then
  54.             ck = True
  55.         ElseIf x5 = y5 Then
  56.             ck = True
  57.         ElseIf x6 = y6 Then
  58.             ck = True
  59.         End If
  60.         If ck Then i = i + 1
  61.     Next
  62.     '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  63.     t = Timer - t
  64.     MsgBox CStr(t) & "   i=" & CStr(i)
  65. End Sub

复制代码
在我的电脑上 test1在任何情况下耗时稳定在 2.2s左右
                       test2在x1-x6 与y1-y6两两相等的时候耗时约0.26s,在极端的情况下(两两不相等)耗时0.5s左右
总体来说test2比test1快4倍左右。

刚刚楼上的回帖我采用的是用数组储存那12个变量,然后用双循环判断是否相等,如果遇到相等则退出循环,确认条件成立,结果一开始我测试的数据是12个变量两两相等的情况,耗时大约0.53s左右,当时急急忙忙回帖,回完了之后才发现测试的有问题,于是马上弄了个两两不相等的情况测试,发现在极端情况下,效率极低,耗时居然达到了7.2s左右

所以接着有帮上楼给删了,重新像本楼这样写。


此楼结果仍然错误!

[ 本帖最后由 Moneky 于 2009-12-20 01:37 编辑 ]

TA的精华主题

TA的得分主题

发表于 2009-12-20 01:09 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
首先表示感谢
说明一下:
      X和Y本来是两个数组,为了提高速度把数组替换为一般BYTE型变量(优化一次)。另外重点需要说明的是两个数组之间并不存在对应关系,只要数组X中任意一个元素与数组Y中任意一个元素相等就算成立,这也是我原来代码表达的含义。
      如果我没有理解错的话,楼主给出的代码是按对应关系判断,这样的判断偏离了题意,会产生错误的结果。不知道我理解的是否正确
          对于布尔运算在计算机内部是如何操作的,我一无所知,所以楼主前面的优化代码,我基本上不理解 ,也不知道如何套用。 所以请楼主多多支持。
      我原来的程序运行一次42分钟,通过吸取楼主的优化措施已经缩短到15分钟。我在84楼提出的需要优化的代码,是程序中调用最频繁的部分,消耗的时间最多(经过1次优化后还占总时间的80%以上),不知道能否再优化。请楼主指点!

[ 本帖最后由 老伙计2008 于 2009-12-20 01:17 编辑 ]

TA的精华主题

TA的得分主题

 楼主| 发表于 2009-12-20 01:42 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
原帖由 老伙计2008 于 2009-12-20 01:09 发表
首先表示感谢
说明一下:
      X和Y本来是两个数组,为了提高速度把数组替换为一般BYTE型变量(优化一次)。另外重点需要说明的是两个数组之间并不存在对应关系,只要数组X中任意一个元素与数组Y中任意 ...

86楼的代码确实是错误的,是我疏忽了。我觉得你的问题可以看成判断两个数组是否有交集的问题,数组元素少的话照你原来那样写,或者是把86楼的代码多写几行还可行,但如果数组太大的话,目前我能想到的办法还只是85楼原来的双层循环来判断。不过这样速度还是不如人意,让我们一起再想想办法吧。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-12-22 18:00 , Processed in 0.036104 second(s), 4 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表