|
楼主 |
发表于 2013-3-23 16:07:26
|
显示全部楼层
性能测试.
代码:- Option Explicit
- '仿C语言中的联合体union高效取高低字方法
- '
- '实现思路:
- '通过操作SafeArray来使一个数组的pvData指向目标变量,然后直接访问高低字,就像C里面的union一样
- '
- 'By 嗷嗷叫的老马
- 'http://www.m5home.com/
- Private Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (ByRef Ptr() As Any) As Long
- Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" ( _
- ByRef Destination As Any, _
- ByRef Source As Any, _
- ByVal Length As Long)
- Private Declare Function GetTickCount Lib "kernel32.dll" () As Long
- Private Const UB As Long = 100000000
- Dim myIntegerArr() As Integer, myByteArr() As Integer, myLong As Long
- Dim ppSA As Long, pSA As Long, pvDataOld As Long
- Dim ppSAByte As Long, pSAByte As Long, pvDataOldByte As Long
- Dim rndList() As Long, HiWords() As Integer
- Private Sub Command1_Click()
- Dim I As Long, K As Long
-
- ReDim rndList(UB)
-
- K = GetTickCount
-
- For I = 0 To UB
- myByteArr(0) = Rnd * 255
- myByteArr(1) = Rnd * 255
- myByteArr(2) = Rnd * 255
- myByteArr(3) = Rnd * 255
-
- rndList(I) = myLong
- Next
-
- MsgBox "生成随机数组时间=" & GetTickCount - K & "ms"
- End Sub
- Private Sub Command2_Click()
- Dim I As Long, K As Long
-
- Erase HiWords()
- ReDim HiWords(UB)
-
- K = GetTickCount
-
- For I = 0 To UB
- myLong = rndList(I)
- HiWords(I) = myIntegerArr(0)
- Next
-
- MsgBox "模拟union方案时间=" & GetTickCount - K & "ms"
- End Sub
- Private Sub Command3_Click()
- Dim I As Long, K As Long
-
- Erase HiWords()
- ReDim HiWords(UB)
-
- K = GetTickCount
-
- For I = 0 To UB
- HiWords(I) = zGetLngHigh(rndList(I))
- Next
-
- MsgBox "zGetLngHigh方案时间=" & GetTickCount - K & "ms"
- End Sub
- Private Sub Command4_Click()
- Dim I As Long, K As Long
-
- Erase HiWords()
- ReDim HiWords(UB)
-
- K = GetTickCount
-
- For I = 0 To UB
- HiWords(I) = GetHiWord(rndList(I))
- Next
-
- MsgBox "GetHiWord方案时间=" & GetTickCount - K & "ms"
- End Sub
- Private Sub Command5_Click()
- Dim I As Long, K As Long
-
- Erase HiWords()
- ReDim HiWords(UB)
-
- K = GetTickCount
-
- For I = 0 To UB
- HiWords(I) = aGetLongHigh(rndList(I))
- Next
-
- MsgBox "aGetLongHigh方案时间=" & GetTickCount - K & "ms"
- End Sub
- Public Function zGetLngHigh(ByVal zLong As Long) As Integer
- zGetLngHigh = (zLong And &H7FFF0000) \ &H10000 Or (((zLong And &H80000000) <> 0) And &H8000)
- End Function
- Public Function GetHiWord(ByRef lThis As Long) As Integer
- If (lThis And &H80000000) = &H80000000 Then
- GetHiWord = ((lThis And &H7FFF0000) \ &H10000) Or &H8000
- Else
- GetHiWord = (lThis And &HFFFF0000) \ &H10000
- End If
- End Function
-
- Private Function aGetLongHigh(ByRef mLong As Long) As Integer
- Dim MyBit(3) As Byte
-
- Call CopyMemory(MyBit(0), mLong, 4)
- Call CopyMemory(aGetLongHigh, MyBit(2), 2)
- Erase MyBit
- End Function
- Private Sub Form_Load()
- Command1.Caption = "生成" & UB & "个随机数"
- Command2.Caption = "模拟union方案"
- Command3.Caption = "zGetLngHigh方案"
- Command4.Caption = "GetHiWord方案"
- Command5.Caption = "aGetLongHigh方案"
-
- Call initArray
- End Sub
-
- Private Sub Form_Unload(Cancel As Integer)
- Call FreeArray
- End Sub
-
- Private Sub initArray()
- '初始化数组及指针.
- '
- '将SafeArray结构的pvDara指针改为myLong变量的地址,这样就可以直接访问高低字了.
- '
- '简单来说就是"绑定"数组与myLong变量,让它们实际上使用同一个地址,相当于C里面的union
- '
- ReDim myIntegerArr(1) '与要访问的变量的长度相同.这里是要把Long分成两个Integer来访问,那就是0,1两个成员.
- myLong = VarPtr(myLong) '把自己的地址放在自己里面
-
- ppSA = VarPtrArray(myIntegerArr) '得到指向SafeArray结构指针的指针(有点绕,就是指针的指针...- -!!)
- Call CopyMemory(pSA, ByVal ppSA, 4) '得到SafeArray指针
-
- MsgBox "pSA=" & Hex(pSA)
-
- Call CopyMemory(pvDataOld, ByVal pSA + 12, 4) '保存之前真数组的指针
- Call CopyMemory(ByVal pSA + 12, myLong, 4) '设置myLong的指针为真数组指针
-
- ReDim myByteArr(3) '与要访问的变量的长度相同.
- myLong = VarPtr(myLong) '把自己的地址放在自己里面
-
- ppSAByte = VarPtrArray(myByteArr) '得到指向SafeArray结构指针的指针(有点绕,就是指针的指针...- -!!)
- Call CopyMemory(pSAByte, ByVal ppSAByte, 4) '得到SafeArray指针
-
- MsgBox "pSAByte=" & Hex(pSAByte)
-
- Call CopyMemory(pvDataOldByte, ByVal pSAByte + 12, 4) '保存之前真数组的指针
- Call CopyMemory(ByVal pSAByte + 12, myLong, 4) '设置myLong的指针为真数组指针
- End Sub
-
- Private Sub FreeArray()
- '恢复原来申请的真数组指针,并释放数组
- '
- Call CopyMemory(ByVal pSA + 12, pvDataOld, 4) '恢复myLong的指针为之前申请的真数组指针
- Erase myIntegerArr()
-
- Call CopyMemory(ByVal pSAByte + 12, pvDataOldByte, 4) '恢复myLong的指针为之前申请的真数组指针
- Erase myByteArr()
- End Sub
复制代码 结果:- 把电脑设置为自动性能模式,不做编译优化,结果如下:
-
- 生成1亿个LONG随机数=53045ms
- 模拟union方案=1462ms
- zGetLngHigh方案=5703ms
- GetHiWord方案=9453ms
- aGetLongHigh方案=64188ms
复制代码- 把电脑设置为最高性能模式,不做编译优化,结果如下:
-
- 生成1亿个LONG随机数=45047ms,提速17%
- 模拟union方案=1203ms,提速21%
- zGetLngHigh方案=4469ms,提速27%
- GetHiWord方案=6531ms,提速44%
- aGetLongHigh方案=46797ms,提速37%
复制代码- 电脑性能设置为自动性能模式,再把编译选项中的高级优化全勾上,结果如下:
-
- 生成1亿个LONG随机数=54719ms,降低3%
- 模拟union方案=1094ms,提速33%
- zGetLngHigh方案=5281ms,提速7%
- GetHiWord方案=8015ms,提速17%
- aGetLongHigh方案=59641ms,提速7%
复制代码- 电脑性能设置为最高性能,再把编译选项中的高级优化全勾上,火力全开了,结果如下:
-
- 生成1亿个LONG随机数=41015ms,提速29%
- 模拟union方案=703ms,提速107%
- zGetLngHigh方案=4094ms,提速39%
- GetHiWord方案=5890ms,提速60%
- aGetLongHigh方案=46515ms,提速37%
复制代码 有点意思,哈哈.
看来编译优化对于性能的提高还是很明显的啊.
不过对函数的调用几乎就没什么用了,比如生成随机数组时,RND函数是VB6内部已经编译好的,不会再二次编译了,所以没什么效果. |
|