Re: [ASP ] 大量String串接動作拖垮效能

看板Visual_Basic作者 (喵喵叫的蜜蜂貓)時間17年前 (2007/03/12 13:28), 編輯推噓4(403)
留言7則, 4人參與, 最新討論串3/4 (看更多)
※ 引述《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
剛剛才注意到討論的不是VB6, ASP自己研究吧XD
03/12 13:57, 1F

03/12 13:57, , 2F
不過觀念應該差不了太多就是了
03/12 13:57, 2F

03/12 22:15, , 3F
感恩 :D
03/12 22:15, 3F

03/13 09:14, , 4F
是用.NET嗎? 如果是何不用StringBuilder?
03/13 09:14, 4F

03/13 18:58, , 5F
樓上的 原文和這篇文章都寫了 VB6 和 非.net -_-;;
03/13 18:58, 5F

03/14 19:10, , 6F
原po是 ASP
03/14 19:10, 6F

03/14 19:11, , 7F
吧o.o
03/14 19:11, 7F
文章代碼(AID): #15zEKNoj (Visual_Basic)
討論串 (同標題文章)
文章代碼(AID): #15zEKNoj (Visual_Basic)