Re: [ASP ] 大量String串接動作拖垮效能
※ 引述《TonyQ (骨頭)》之銘言:
: ※ 引述《TonyQ (骨頭)》之銘言:
: → TonyQ:問題已解決 , 不過是用其他方式解決 , 不曉得這問題是否有解 03/03 23:20
: 推 fumizuki:把一百筆串起來還是某些欄位串成同一個欄位? 03/04 19:15
: 推 fumizuki:如果是某些欄位串成同一個欄位 sql 查詢語法就可以了@@ 03/04 19:15
: 每一個欄位是一個字串,
: 我今天的問題不是在於SQL的問題。
: 而是在於我兜SQL查出資料來之後,
: 我沒有辦法把所有字串疊加起來。:)
: 請就它的本意去思考就好
: 如果我今天有2000到一萬個個字串 要疊加,
: 不曉得有沒有辦法解決效能的問題?:P
VB6的String預設是可變長度
但內部實做其實是一直產生新的刪除舊的
另一種方是是用不可變長度,但是我實測沒有比較快,而且又有長度限制...
那麼就需要使用比較低階的方法了,用講的太麻煩,讓測試程式來說話
'使用API RtlMoveMemory,採傳址方式
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory"
(ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)
Private Sub Form_Load()
Dim a As String, c As Long
Dim b As String, lb As Long, d As String, lend As Long
Debug.Print Timer '時間開始
For c = 1 To 50000
a = a & Format(c, "00000")
Next c
Debug.Print Timer '一般方法結束,特殊方法開始
'建立一個「足夠長度」的字串,並填入0
b = String(500000, Chr(0))
lb = StrPtr(b) '預先紀錄字串b的記憶體起始位置
For c = 1 To 50000
d = Format(c, "00000") '因為要CopyMemory, 所以要先儲存要累加的字串
'其實d在迴圈中也會不斷重新製造, 所以也可以想
'辦法用類似的方法避免掉一直重新製造
lend = LenB(d) '注意要用LenB而非Len, 因為VB6是Unicode的
CopyMemory lb, StrPtr(d), lend '將d所在字串位址中長度lend複製到位址lb
lb = lb + lend '目標位址偏移計算
Next c
b = Left(b, InStr(b, Chr(0)) - 1) '將b結尾多餘的0去掉
Debug.Print Timer '特殊方法結束
Debug.Print a = b '驗證結果為True(字串內容相同)
End
End Sub
=======================
你可以發現這兩種方法,執行效率差了約100倍
而且隨著c迴圈值的增加,時間差異是成等比級數上升
因為a的重新產生越來越花時間...
注意!由於CopyMemory直接控制記憶體存取,將繞過VB6的記憶體安全機制
如果複製的來源或目標超出預先定義的範圍,將可能導致程式例外錯誤
在測試這一類API時,建議每次執行前都要存檔
在VB6的 工具-選項-環境-程式於執行前: 詢問是否儲存變更
建議把它勾起來
======================
此外還有另一種方法
Private Sub Form_Load()
Dim a As String, c As Long
Dim b As String, lb As Long, d As String, lend As Long
Debug.Print Timer '採用CopyMemory方式開始
b = String(5 * 10 ^ 7, Chr(0))
lb = StrPtr(b)
For c = 1 To 999999
d = Format(c, "000000")
lend = LenB(d)
CopyMemory lb, StrPtr(d), lend
lb = lb + lend
Next c
b = Left(b, InStr(b, Chr(0)) - 1)
Debug.Print Timer '採用CopyMemory方式結束,採用字串陣列方法開始
Dim z(0 To 2 * 10 ^ 7) As String '故意用比較長的長度
'來驗證z的長度可以設到很大
For c = 1 To 999999
z(c) = Format(c, "000000")
Next c
a = Join(z, "")
Debug.Print Timer '採用字串陣列方式結束
Debug.Print a = b '驗證結果為True
End
End Sub
======================
當然,陣列方法還是沒有CopyMemory方式快,但是中間差距很小
連續累加將近100萬個長度為6的字串差距還不到一秒鐘
而且因為沒有動用到API,就沒有異常終止的問題
另外在比較陣列跟CopyMemory方法時,請不要拿原始方法並列
可能要跑很久很久很久......
--
短句釋義: 書店都不書店了
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.115.204.46
→
03/12 13:57, , 1F
03/12 13:57, 1F
→
03/12 13:57, , 2F
03/12 13:57, 2F
推
03/12 22:15, , 3F
03/12 22:15, 3F
推
03/13 09:14, , 4F
03/13 09:14, 4F
推
03/13 18:58, , 5F
03/13 18:58, 5F
推
03/14 19:10, , 6F
03/14 19:10, 6F
→
03/14 19:11, , 7F
03/14 19:11, 7F
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 3 之 4 篇):