Variant Array 的快速複製? |
答題得分者是:william
|
shaofu
高階會員 發表:5 回覆:136 積分:103 註冊:2003-01-07 發送簡訊給我 |
轉貼 Programmer 深度論壇的問題..
我想不到較快的方法, 大家來討論看看 :P 原址:
================================
http://forum.vclxx.org/topic.php?TOPIC_ID=25539&FORUM_ID=8&CAT_ID=2&Topic_Title=variantªº§ֳt½ƻs?&Forum_Title=Pascal 內容:
================================
aryData : variant;
aryNew : variant; 如果處理後aryData是一個內含2維variant陣列的variant變數
也就是aryData[0,0]至aryData[5,100]都有variant型態的資料 然後
aryNew:=VarArrayCreate([0,20],varVariant); 請問如果不用迴圈一一指定,
要如何快速將aryData[3,20]至aryData[3,50]快速複製到aryNew[0..20] ? 發表人 - shaofu 於 2003/05/12 14:03:31
|
william
版主 發表:66 回覆:2535 積分:3048 註冊:2002-07-11 發送簡訊給我 |
If the element types of the source is fixed (e.g. longint), you can calculate the address of the data needed and do a move, which should be much more faster.
type PVarArray = ^TVarArray; TVarArray = array[0..100] of variant; var V,N: variant; i,j,t1,t2,t3,t4: integer; PV,PN: PVarArray; f: boolean; begin V := VarArrayCreate([0,5,0,100],varVariant); for i := 0 to 5 do for j := 0 to 100 do V[i,j] := random; N := VarArrayCreate([0,30],varVariant); t1 := GetTickCount; for j := 1 to 10000 do // do 10000 times for i := 0 to 30 do N[i] := V[3,20 i]; t2 := GetTickCount; VarClear(N); N := VarArrayCreate([0,30],varVariant); PV := VarArrayLock(V); PN := VarArrayLock(N); try t3 := GetTickCount; for j := 1 to 10000 do // do 10000 times for i := 0 to 30 do PN^[i] := V[3,20 i]; t4 := GetTickCount; finally VarArrayUnLock(V); VarArrayUnLock(N); end; f := True; for i := 0 to 30 do f := f and (N[i]=V[3,i 20]); if f then ShowMessage(Format('1: %d%s2: %d',[t2-t1,#13 #10,t4-t3])) else ShowMessage('error'); end;發表人 - william 於 2003/05/12 12:37:19 |
shaofu
高階會員 發表:5 回覆:136 積分:103 註冊:2003-01-07 發送簡訊給我 |
|
william
版主 發表:66 回覆:2535 積分:3048 註冊:2002-07-11 發送簡訊給我 |
Try it: < class="code">type
PVarArray = ^TVarArray;
TVarArray = array[0..10000] of variant;
var
V,N: variant;
i,j,t1,t2,t3,t4: integer;
PV,PN: PVarArray;
f: boolean;
begin
V := VarArrayCreate([0,5,0,100],varVariant);
for i := 0 to 5 do
for j := 0 to 100 do
V[i,j] := random;
N := VarArrayCreate([0,30],varVariant);
t1 := GetTickCount;
for j := 1 to 10000 do // do 10000 times
for i := 0 to 30 do
N[i] := V[3,20 i];
t2 := GetTickCount;
VarClear(N);
N := VarArrayCreate([0,30],varVariant);
PV := VarArrayLock(V);
PN := VarArrayLock(N);
try
t3 := GetTickCount;
for j := 1 to 10000 do // do 10000 times
for i := 0 to 30 do
PN^[i] := PV^[3 (20 i)*6];
t4 := GetTickCount;
finally
VarArrayUnLock(V);
VarArrayUnLock(N);
end;
f := True;
for i := 0 to 30 do
f := f and (N[i]=V[3,i 20]);
if f then
ShowMessage(Format('1: %d%s2: %d',[t2-t1,#13 #10,t4-t3]))
else
ShowMessage('error');
end;
|
jackkcg
站務副站長 發表:891 回覆:1050 積分:848 註冊:2002-03-23 發送簡訊給我 |
william
還真正是 利害的高手 配服配服 *********************************************************
哈哈&兵燹
最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好 Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知
K.表Knowlege 知識,就是本站的標語:Open our mind to make knowledge together!
希望能大家敞開心胸,將知識寶庫結合一起
------
********************************************************** 哈哈&兵燹 最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好 Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知 K.表Knowlege 知識,就是本站的標語:Open our mind |
shaofu
高階會員 發表:5 回覆:136 積分:103 註冊:2003-01-07 發送簡訊給我 |
|
syntax
尊榮會員 發表:26 回覆:1139 積分:1258 註冊:2002-04-23 發送簡訊給我 |
其實 Move 是可以用的 !! move(aryData[0,0],aryData[5,100],sizeof(variant)*count)
基本上 variant 也是固定長度的!!也就是佔用等長度的記憶體空間。
所以
V := VarArrayCreate([0,5,0,100],varVariant); for i := 0 to 5 do for j := 0 to 100 do V[i,j] := 999; N := VarArrayCreate([0,30],varVariant); for i := 0 to 30 do N[i] := 333; PV := VarArrayLock(V); PN := VarArrayLock(N); move(PV[0],PN[0],SizeOf(Variant)*5);你可以驗證 N 的前 5 筆資料,是 999 而不是原來的 333 所以如果是純粹複製,move 還是最快的 只是你要知道如何去變通!! 引言: 真的可以了 分析這個問題, 我有兩個盲點 > > 感謝 > 發表人 - >>< face="Verdana, Arial, Helvetica"> |
shaofu
高階會員 發表:5 回覆:136 積分:103 註冊:2003-01-07 發送簡訊給我 |
|
shaofu
高階會員 發表:5 回覆:136 積分:103 註冊:2003-01-07 發送簡訊給我 |
可讀性高一點的寫法
< class="code">
type
TVarArraySrc = array[0..100, 0..5] of variant; // 倒過來 Mapping
TVarArrayDest = array[0..30] of variant;
var
V,N: variant;
i,j,t1,t2,t3,t4: integer;
PSrc: ^TVarArraySrc;
PDest: ^TVarArrayDest;
f: boolean;
begin
V := VarArrayCreate([0,5,0,100],varVariant);
for i := 0 to 5 do
for j := 0 to 100 do
V[i,j] := i*100 j;
N := VarArrayCreate([0,30],varVariant);
t1 := GetTickCount;
for j := 1 to 10000 do // do 10000 times
for i := 0 to 30 do
N[i] := V[3,20 i];
t2 := GetTickCount;
VarClear(N);
N := VarArrayCreate([0,30],varVariant);
PSrc := VarArrayLock(V);
PDest := VarArrayLock(N);
try
t3 := GetTickCount;
for j := 1 to 10000 do // do 10000 times
for i := 0 to 30 do
PDest[i] := PSrc[20 i, 3]; // 不連續的 index
>>
|
syntax
尊榮會員 發表:26 回覆:1139 積分:1258 註冊:2002-04-23 發送簡訊給我 |
呵呵!你說的是這個阿!那就更簡單了!
查了一下!你就會發現 VarArrayCreate 是 WinAPI 的包裝
所以囉!原因知道了嗎?
當單維度陣列,所有編譯器都視同一連續記憶體來實做,所以 Move 最快
而當二維以上的陣列,則會因編譯器不同而有不同實做方式,不過其記憶體空間都是連續的!並沒有你所說的不連續(因該是說你的用詞不恰當,所以我才誤會囉!)
一般來說,陣列的記憶體實做分為
1. row major
2. column mahor
Wins32 系列屬於 2. 而 C & Pascal 則採用 1. 的規則 考慮如下陣列 A[X,Y],column major 陣列對應到記憶體時,是以 Y 優先放入,因此在記憶體內是 A[0,0],A[0,1],A[0,2],A[0,3]...A[1,0],A[1,1]..等等,而 row major 則是以 X 為優先,A[0,0],A[1,0],A[2,0],A[3,0]...A[0,1],A[1,1]..等等 Window 是以 Wins32 位為主介面系統,採用 column major 原則,C & Pascal 採用 row major 原則,所以當用 VarArrayCreate 創造出來的陣列是 column major 與 Delphi 創造的是不同的,因此在對應上要轉個90度,不過通常編譯器會幫你處理,所以用索引的方式會較慢!因為還包含了額外的處理程式碼(這是編譯器自動加入的),而用 PV := VarArrayLock(V); 則是傳回陣列的第一個元素位置,如此直接存取當然較快,只是你就必須自己處理(因編譯器差異所導致的)陣列對應,只是這種差異就無法使用 move 來搬移了,這是先天上的差異,除非機器設計原理改變,不然永遠是這樣,就如同汽車不會飛,除非有新發明,即使軟體在進步也是無法改變硬體的限制! 所以並沒有你所說的不連續,因為沒有人規定X,Y座標一定要由X 開始遞增啊!兩者都是連續的使用記憶體空間,只是開始的軸向不一樣而已! 那三維以上的呢?一樣!將三維其拆成兩個二維,然後套用 1. 或 2. 的原則! 其實會有這種問題發生,乃是因為知識的不足,才會產生,如果相關知識充足,這個問題根本不存在!在下不是在說各位用功不夠!!絕無貶低各位的意思!只是提醒大家要多看書學習! 提供幾本書,有談到這個主題的: 1. {William Stallings}, Computer Organization & Architecture DESIGNING FOR PERFORMANCE
2. {Robert W. Sebesta} , Concepts of Programming Languages
3. {Silberschatz , Galvin , GaGne} , Operating System Concepts 希望這樣能釐清你的觀念與疑慮 !
引言: Syntax 兄誤會我的意思了 < > > 為甚麼會這樣.. 我就不清楚了< > 發表人 - > 發表人 - syntax 於 2003/05/14 17:24:59 發表人 - syntax 於 2003/05/15 11:26:04 |
syntax
尊榮會員 發表:26 回覆:1139 積分:1258 註冊:2002-04-23 發送簡訊給我 |
|
shaofu
高階會員 發表:5 回覆:136 積分:103 註冊:2003-01-07 發送簡訊給我 |
|
shaofu
高階會員 發表:5 回覆:136 積分:103 註冊:2003-01-07 發送簡訊給我 |
|
syntax
尊榮會員 發表:26 回覆:1139 積分:1258 註冊:2002-04-23 發送簡訊給我 |
補充一下
Lock 呼叫的是 SafeArrayAccessData
目的是:
是用來將 LockCount 值加 1 並傳回 第一筆資料的位址
不是用來鎖定該陣列
LockCount 是給作業系統運作所需之
細節可以參考 Wins32 SafeArray相關函式說明
引言: 另外"不連續"這個字很容易讓大家誤會, 在此更正! Lock 的那塊 Memory 當然是一整塊連續的 Memory (Lock 的目的), 只是因為 Memory Mapping (row major, column major) 的方式不同, 造成我認為"不連續"的現象! 我還是該多翻書了 @@ 發表人 - shaofu 於 2003/05/14 17:59:29 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |