線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:8417
推到 Plurk!
推到 Facebook!
[<<] [1] [2] [>>]

請問比對圖片想使用多執行緒的方式,但還是單線程問題

答題得分者是:aftcast
macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#1 引用回覆 回覆 發表時間:2011-07-21 10:59:51 IP:219.87.xxx.xxx 訂閱
請問一下各位,我要做圖形比對的程式,但是因為會跑在多核的機器上,所以想用multithread的方式來執行,增加效能,目前作法如下,但是好像還是跑單線程的方式,而且好像比循續的方式還要久(看起來是二倍左右的時間),不知小弟是不是那邊的問題,可能是觀念問題,上了ktop/google查過,目前能夠理解的部份是不是因為我把宣告的三張圖(二張比對的圖,與一張比對完後的圖)宣告在form上面造成只有main thread的執行?還是我沒有用safe thread來保護線程?有google到有人提說是vcl只能用單線程執行,還是那邊出問題,請有經驗的人幫忙告知小弟,感謝您花時間閱讀問題,謝謝。

1 我在form上面宣告三個tbitmap,二個為讀檔用的,一個為存比對完結果用的圖
2 接著建立thread,一開始先讓thread先暫停
FillBMP[i-1] := TFillBMP.Create(True) ;
FillBMP[i-1].FreeOnTerminate := True;
FillBMPHwnd[i-1] := FillBMP[i-1].Handle ;
3 然後啟動所有的thread,並設定每一個thread到各別的核心上(目前看來好像都沒跑到100%)
FillBMP[i].Resume;
SetThreadAffinityMask(FillBMP[i].Handle, CPU_Mask[i]);
4 最後用WaitForMultipleObjects來判斷是否全圖比對完,才輸出圖片
while (WaitForMultipleObjects(CPUNum, PWOHandleArray(FillBMPHwnd),
True, INFINITE) = WAIT_TIMEOUT) do
begin
Sleep(1);
end;
5 thread的部份直接在TFillBMP.Execute中直接呼叫處理比對的function
procedure TFillBMP.Execute;
begin
//Synchronize(CMPR); //加這個好像會停住
CMPR();
end;
請幫忙看一下小弟是不是觀念上的問題,或是寫法那邊要注意,還是請提供一些可參考的資料,謝謝各位。

------
DELPHI初學者
mitchellhu
一般會員


發表:22
回覆:51
積分:14
註冊:2007-06-12

發送簡訊給我
#2 引用回覆 回覆 發表時間:2011-07-22 10:11:13 IP:123.204.xxx.xxx 訂閱
 昨天蕭沖大師有在捷康開了一場multithread的教學。
他有作了一個類似你的case來演示。
請個部份請問他應該有好的答案。
另外,對於你的題目,比對圖檔這部份。
我很好奇,你如何訂義2張圖檔的差異性呢?
而且可以在將差異顯示在第3張圖上?
是所有格式的圖檔都可以對比嗎?
bmp, jpg, ai, cdr都可嗎?
那pdf呢?
若能,請指點一些想法可以嗎?


macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#3 引用回覆 回覆 發表時間:2011-07-22 10:54:02 IP:219.87.xxx.xxx 訂閱
先謝謝你的回覆,
唉,昨天要上課,本來也想去上這門課的,之前就常到蕭沖大師的blog上去看一些資料,圖形這個部份我也不是很了解,程式也是從GOOGLE上一點一點組成的,目前只有用在bmp,其它格式我可能也不是很了解呢,抱歉幫不上忙,
我查過ktop,基本上我同事用vc 寫的,大致上與我相同,但是他們的cpu(多核)都可以完成,而且比對過程式碼的部份,也很相近,所以才會很麻煩,另外一點就是我對於這個部份可能不是很了解也是一個問題,所以最近查了一些資料,但也沒有明確的方向,所以才想詢問一下,是不是有經驗的人可以指導小弟,謝謝。

===================引 用 mitchellhu 文 章===================
昨天蕭沖大師有在捷康開了一場multithread的教學。
他有作了一個類似你的case來演示。
請個部份請問他應該有好的答案。
另外,對於你的題目,比對圖檔這部份。
我很好奇,你如何訂義2張圖檔的差異性呢?
而且可以在將差異顯示在第3張圖上?
是所有格式的圖檔都可以對比嗎?
bmp, jpg, ai, cdr都可嗎?
那pdf呢?
若能,請指點一些想法可以嗎?


------
DELPHI初學者
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#4 引用回覆 回覆 發表時間:2011-07-22 11:51:34 IP:210.64.xxx.xxx 訂閱
 while (WaitForMultipleObjects(CPUNum, PWOHandleArray(FillBMPHwnd),
True, INFINITE) = WAIT_TIMEOUT) do
begin
Sleep(1);
end;

那個INFINITE應該要改成一個數值,才會timeout,否則永遠不會timeout,所以 sleep(1)的好處從來不會發生。

如果說
//Synchronize(CMPR); //加這個好像會停住
CMPR();

那麼表示cmpr這個方法的寫法是關鍵,裡面有放 sleep ? critical section? waitforxxxxobjecs? 還是?? 最好po一下文看看

===================引 用 macchen 文 章===================

------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
jcjroc
高階會員


發表:21
回覆:276
積分:114
註冊:2002-09-18

發送簡訊給我
#5 引用回覆 回覆 發表時間:2011-07-23 03:00:49 IP:60.248.xxx.xxx 訂閱
1.多大張的圖?用不到Thread吧!
2.用TBitmap 慢死你!!!
3,嗯!!圖很大一張,而且目標機器是多核的CPU,用Multi thread來展現一下速度吧!!!阿.......用了VCL處理圖形.....唉!!!死路一條.

給你個方向吧!!!
1.去用力地啃一下BMP的格式!!
2.如果圖形來源是檔案,那再瞄一下CreateFile,CreateFileMapping,MapViewOfFile.
3.如果還要顯示比對(運算)後的結果,那再蹬一眼CreateWindow,GetDC,SelectObject,DeleteObject,CreateDIBSection
4.如果第3點成立,嗯!!來點酷一點的,青一眼InvalidateRect
5.啥!!這還不夠炫,還要再加上zoom in跟zoom out........那含著眼淚再看看
SetMapMode,SetWindowExtEx,SetViewportExtEx.
macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#6 引用回覆 回覆 發表時間:2011-07-25 11:27:25 IP:219.87.xxx.xxx 訂閱
非常感謝affcast大的回覆,先回答一下,下面的問題
1 那個INFINITE應該要改成一個數值,才會timeout,否則永遠不會timeout,所以 sleep(1)的好處從來不會發生。
這個已經拿掉了,之前是以為沒加所以會慢,也是觀念問題沒搞好。

2 那麼表示cmpr這個方法的寫法是關鍵,裡面有放 sleep ? critical section? waitforxxxxobjecs? 還是?? 最好po一下文看看
這個function裡面什麼都沒有加呢,只有單純的比對圖片的程式碼,附上程式的部份,麻煩再指導小弟一下,感激不盡。

[code delphi]
procedure TFillBMP.CMPR;
var
Y, NX, TBit, CX, TX, TBitIdx, CBitIdx, CBit: Integer;
TRIPa, EZPa, NewPa: PByteArray;
NewByte: string;
CXFill: Boolean;
newbin: string;
i: Integer;
begin
for Y := StartY to EndY do
begin
if (Y TTop) > (TRBmp.Height - 1) then
Break;
if (Y CTop) > (EZBmp.Height - 1) then
Break;
TRIPa := TRBmp.ScanLine[Y TTop];
EZPa := EZBmp.ScanLine[Y CTop];
NewPa := NewBMP.ScanLine[Y CTop];
NX := 0;
TBit := 0;
TX := TBytePos;
CX := CBytePos;
NewByte := '';
TBitIdx := OTBitIdx;
CBitIdx := OCBitIdx;
CXFill := False;
while true do
begin
if not CXFill then //2011.7.20 add
TBit := TRIPa[TX] shr TBitIdx and 1;
CBit := EZPa[CX] shr CBitIdx and 1;
if not CXFill then //2011.7.20 add
begin
if TBit = CBit then
NewByte := NewByte '0'
else
begin
if (TBit = 0) and (CBit = 1) then
NewByte := NewByte '1'
else
NewByte := NewByte '0';
end;
end
else
NewByte := NewByte '0';
if Length(NewByte) = 8 then
begin
NewPa[NX] := StrToInt('0x' BinStrToHex(NewByte));
NewByte := '';
inc(NX);
end;
if not CXFill then //2011.7.20 add
begin
dec(TBitIdx);
if TBitIdx < 0 then //Length(TLine) then
begin
inc(TX);
TBitIdx := 7;
end;
end;
dec(CBitIdx);
if CBitIdx < 0 then //Length(CLine) then
begin
inc(CX);
CBitIdx := 7;
end;
if CX > (TW div 8) - 1 then //2011.7.20 add
CXFill := True;
if CX > (W div 8) - 1 then
begin
if Length(NewByte) <> 0 then
begin
if length(NewByte) < 8 then
begin
newbin := '';
for i := 0 to 8 - length(NewByte) - 1 do
newbin := newbin '0';
NewByte := NewByte newbin;
end;
NewPa[NX] := StrToInt('0x' BinStrToHex(NewByte));
NewByte := '';
end;
Break;
end;
end;
end;
end;
[/code]


===================引 用 aftcast 文 章===================
while (WaitForMultipleObjects(CPUNum, PWOHandleArray(FillBMPHwnd),
True, INFINITE) = WAIT_TIMEOUT) do
begin
Sleep(1);
end;

那個INFINITE應該要改成一個數值,才會timeout,否則永遠不會timeout,所以 sleep(1)的好處從來不會發生。

如果說
//Synchronize(CMPR); //加這個好像會停住
CMPR();

那麼表示cmpr這個方法的寫法是關鍵,裡面有放 sleep ? critical section? waitforxxxxobjecs? 還是?? 最好po一下文看看

===================引 用 macchen 文 章===================


------
DELPHI初學者
macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#7 引用回覆 回覆 發表時間:2011-07-25 11:33:24 IP:219.87.xxx.xxx 訂閱

===================引 用 jcjroc 文 章===================
1.多大張的圖?用不到Thread吧!
40352*44466,而且會有多張圖要比對,而且速度不夠快才會想用thread,因為cpu都沒有跑滿,才會想用thread的方式。
2.用TBitmap 慢死你!!!
?那請問一下,可以用什麼處理會比較快呢?查google是用scanline的方式就相當快,還是還有別的,請指導小弟一下,謝謝。
3,嗯!!圖很大一張,而且目標機器是多核的CPU,用Multi thread來展現一下速度吧!!!阿.......用了VCL處理圖形.....唉!!!死路一條.
請問一下tbitmap是vcl嗎?查過用vcl好像要用Synchronize,但這又跑回到main thread了?不是還是一樣會比較慢嗎?

給你個方向吧!!!
1.去用力地啃一下BMP的格式!!
2.如果圖形來源是檔案,那再瞄一下CreateFile,CreateFileMapping,MapViewOfFile.
3.如果還要顯示比對(運算)後的結果,那再蹬一眼CreateWindow,GetDC,SelectObject,DeleteObject,CreateDIBSection
4.如果第3點成立,嗯!!來點酷一點的,青一眼InvalidateRect
5.啥!!這還不夠炫,還要再加上zoom in跟zoom out........那含著眼淚再看看
SetMapMode,SetWindowExtEx,SetViewportExtEx.
------
DELPHI初學者
jcjroc
高階會員


發表:21
回覆:276
積分:114
註冊:2002-09-18

發送簡訊給我
#8 引用回覆 回覆 發表時間:2011-07-25 12:56:10 IP:211.23.xxx.xxx 訂閱
答案不是給你了嗎????
macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#9 引用回覆 回覆 發表時間:2011-07-25 13:08:16 IP:219.87.xxx.xxx 訂閱
不好意思,不是很懂呢??答案是什麼?可以再指導小弟一下嗎?不好意思,真的不是很懂你在說什麼呢,謝謝你的回覆。

給你個方向吧!!!
1.去用力地啃一下BMP的格式!!
??格式有什麼特別嗎??
2.如果圖形來源是檔案,那再瞄一下CreateFile,CreateFileMapping,MapViewOfFile.
為什麼要用這三個??
3.如果還要顯示比對(運算)後的結果,那再蹬一眼CreateWindow,GetDC,SelectObject,DeleteObject,CreateDIBSection
我只是要用運算比對資料,你這幾個會用的到嗎??不是很了解,麻煩再告知一下。
4.如果第3點成立,嗯!!來點酷一點的,青一眼InvalidateRect
我沒有要繪圖?為什麼會用到這個??
5.啥!!這還不夠炫,還要再加上zoom in跟zoom out........那含著眼淚再看看
SetMapMode,SetWindowExtEx,SetViewportExtEx.

===================引 用 jcjroc 文 章===================
答案不是給你了嗎????
------
DELPHI初學者
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#10 引用回覆 回覆 發表時間:2011-07-25 13:50:17 IP:210.64.xxx.xxx 訂閱
你好,

大致上看了一下程式。還有個疑問:
TRBmp, EZBmp, NewBMP 這三個是每條thread都用同樣的這三個bmp? (我是bmp的內容是否都一樣?),或是每條thread裡的這三個都是不一樣的。是以什麼方式傳入thread中?這和 同步問題有些關係。可以的話 po 一下 建立起來的那部份。


------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#11 引用回覆 回覆 發表時間:2011-07-25 15:05:10 IP:219.87.xxx.xxx 訂閱
affcast謝謝你的回覆,說明如下,謝謝您。

===================引 用 aftcast 文 章===================
你好,

大致上看了一下程式。還有個疑問:
TRBmp, EZBmp, NewBMP 這三個是每條thread都用同樣的這三個bmp?
是的,就是統一由form讀二個檔案,與將結果輸出到newbmp上,然後存檔。
(我是bmp的內容是否都一樣?),或是每條thread裡的這三個都是不一樣的。
內容都是pf1bit的格式,每個thread中的資料的來源都是相同的。
是以什麼方式傳入thread中?
之前有試過,由form統一宣告這個三變數,分別由form.TRbmp/ form.EZBmp / form.NewBmp的方式來使用,
然後問過使用vc 的人,他們是說傳入pointer的方式,所以我又在改用第二種方式,在therad中建立這三個bmp的pointer,但是還是一樣(也不知是不是我用錯了,我是用tbmp, ebmp, nbmp:^TBITMAP;的方式來宣告的,然後在create thread時將form上的trbmp/ezbmp/newbmp傳入到tbmp/ebmp/nbmp,但是測試結果還是一樣,所以才去找criticalsession,以為是這些thread有用到vcl,所以造成都由main thread 來執行才會變成花二倍時間,麻煩再請指導小弟一下,沒去聽您的課程真是苦惱,因為之前就有看過你提的問題,但一直不是很懂,謝謝。

[code delphi]
SetLength(FillBMP, CPUNum);
SetLength(FillBMPHwnd, CPUNum);

for i := 1 to CPUNum do
begin
FillBMP[i - 1] := TFillBMP.Create(True);
FillBMP[i-1].FreeOnTerminate := True;
FillBMPHwnd[i - 1] := FillBMP[i - 1].Handle;

if i = 1 then
FillBMP[i - 1].StartY := 0
else
FillBMP[i - 1].StartY := ((i-1) * ((H - CTop) div CPUNum)) ;


if i = CPUNum then
FillBMP[i - 1].EndY := H - CTop - 1
else
FillBMP[i - 1].EndY := (i * ((H - CTop) div CPUNum)) - 1;
FillBMP[i - 1].TBytePos := TBytePos;
FillBMP[i - 1].CBytePos := CBytePos;
FillBMP[i - 1].OTBitIdx := OTBitIdx;
FillBMP[i - 1].OCBitIdx := OCBitIdx;
FillBMP[i - 1].TW := TW;
FillBMP[i - 1].W := W;
FillBMP[i - 1].CTop := CTop ;
FillBMP[i - 1].TTop := TTop ;
FillBMP[i - 1].TRBMP := @TRBmp;
FillBMP[i - 1].EZBMP := @EZBmp;
FillBMP[i - 1].NewBMP := @NewBMP;
end;
for i := 0 to CPUNum - 1 do
FillBMP[i].Resume;
WaitForMultipleObjects(CPUNum, PWOHandleArray(FillBMPHwnd),
True, INFINITE) ;
[/code]


這和 同步問題有些關係。可以的話 po 一下 建立起來的那部份。


------
DELPHI初學者
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#12 引用回覆 回覆 發表時間:2011-07-25 17:43:25 IP:210.64.xxx.xxx 訂閱
你好,

我終於感覺上是猜出你的想法了 :-)

如果上面我猜的沒錯的話。你要做的其實是「並行運算」。但目前你的做法是完全不一樣的。

1/ 其實你只要一條thread就好,就算你有二個cpu。(我猜你是二個,也因此你得到的是二倍時間!!)

2/ windows理論上會去計算二個cpu怎麼用。如果你還是一定要自己來配…那問題就變難了。你必需:

a 把比對的演算法猜解成幾個部份 : 比如說,比圖的上半部與比圖的下半部二個部份。
b 接著起二條thread,其中一個算上部份。另一個算下半部。可能的話也可以指定哪個cpu 核用1,哪個用2…
c 最後把二個結果整合一下。
d 當然,以上的做法就有「同步的問題」。但bmp的同步只需要用TBmp->Canvas->Lock 與 TBmp->Canvas->Unlock 這二個。不需要用synchronized,否則一如你測出來的。感覺好像當了! 因為那麼多的工作全轉到 main thread上去跑,於是main thread都在這個計算,就沒時間處理其他的事件了!

以上。

但我個人覺得那樣不會有什麼很大的幫助,除非你自己拆解演算法很精,才有一些些的幫助。
建議還是 單一條thread來處裡 計算就夠了! 最多把該thread的 priority 拉到最高再用SetThreadAffinityMask恉定該thread至另一個核上。






------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
編輯記錄
aftcast 重新編輯於 2011-07-25 03:52:43, 註解 無‧
macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#13 引用回覆 回覆 發表時間:2011-07-26 09:07:31 IP:219.87.xxx.xxx 訂閱

===================引 用 aftcast 文 章===================
你好,

我終於感覺上是猜出你的想法了 :-)
謝謝您的回覆,原來是我話沒說清楚,才會讓大家搞不懂我的問題在那,謝謝大大願意花時間幫忙小弟釐清觀念問題。

如果上面我猜的沒錯的話。你要做的其實是「並行運算」。但目前你的做法是完全不一樣的。
請問一下「並行運算」不是也是指將同一個工作拆成多個thread讓多個核心來個別處理的意思嗎?小弟的說法不知有沒有問題

1/ 其實你只要一條thread就好,就算你有二個cpu。(我猜你是二個,也因此你得到的是二倍時間!!)
這裡就不是很了解意思了?因為我之前用一條thread的時候,雙核cpu卻只有一核會跑到100%,所以才會想拆成二個thread,然後再用SetThreadAffinityMask的方式,將拆開的部份分別指定到cpu的核心上,這樣說法不知有沒有錯。

2/ windows理論上會去計算二個cpu怎麼用。如果你還是一定要自己來配…那問題就變難了。你必需:
請問一下,開二個thread,然後用SetThreadAffinityMask不是就是將這二個thread指定到這二個核心上嗎?因為這樣指定後cpu使用率變成70~80%了,但時間卻沒什麼變,這點我最覺的奇怪。

a 把比對的演算法猜解成幾個部份 : 比如說,比圖的上半部與比圖的下半部二個部份。
我是這樣子做的沒錯,如四核心則拆成四分,quad的方式來處理各別的資料,最後用waitformultiobjects來做結束
b 接著起二條thread,其中一個算上部份。另一個算下半部。可能的話也可以指定哪個cpu 核用1,哪個用2…
就是用SetThreadAffinityMask來指定的
c 最後把二個結果整合一下。
應該是指waitformultiobjects嗎??
d 當然,以上的做法就有「同步的問題」。
所以您的意思是指用「tbitmap」就是vcl嗎?不然怎麼會有「同步的問題」還是因為什麼原因(請指導一下小弟,因為小弟就是這邊觀念有問題,所以才會搞不懂為什麼會變成二倍時間)
但bmp的同步只需要用TBmp->Canvas->Lock 與 TBmp->Canvas->Unlock 這二個。
請問這個「TBmp->Canvas->Lock」的部份是加在for的下方嗎?還是加在那邊,因為我加在for的下方,時間還是比單thread的二倍久,而只加在newbmp的部份,時間還是比較久,但是比for的下面時間要快,是我加錯地方嗎?
不需要用synchronized,否則一如你測出來的。感覺好像當了! 因為那麼多的工作全轉到 main thread上去
跑,於是main thread都在這個計算,就沒時間處理其他的事件了!
所以我拆成二個thread的做法有缺失,仍然還是用main thread在處理的意思嗎,所以才會造成二倍時間的關係。

以上。

但我個人覺得那樣不會有什麼很大的幫助,除非你自己拆解演算法很精,才有一些些的幫助。
請問因為我問別人,他們也是說只要將圖片拆解,然後寫入即可增加計算速度,所以我才會用這種方式來處理,他們是用vc 寫的,還是因為我對delphi的觀念有問題,所以才無法增加速度?
建議還是 單一條thread來處裡 計算就夠了! 最多把該thread的 priority 拉到最高再用SetThreadAffinityMask恉定該thread至另一個核上。
請問藍字的地方,是指說還是用二個thread的方式來處理嗎?不是很能了解這段話的意義。

謝謝你花時間幫忙小弟了解這個問題,再麻煩指導小弟,讓小觀念能更清楚,謝謝您的幫助。





------
DELPHI初學者
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#14 引用回覆 回覆 發表時間:2011-07-26 10:37:47 IP:210.64.xxx.xxx 訂閱


>>請問一下「並行運算」不是也是指將同一個工作拆成多個thread讓多個核心來個別處理的意思嗎?小弟的說法不知有沒有問題
你的說法是正確的。但多數人使用multithread的原因並不是把「一個」工作「切成n個」並運用multithread處理。因為並行運算也有可能把工作切到不同的電腦上來算。

>>這裡就不是很了解意思了?因為我之前用一條thread的時候,雙核cpu卻只有一核會跑到100%,所以才會想拆成二個thread,然後再用SetThreadAffinityMask的方式,將拆開的部份分別指定到cpu的核心上,這樣說法不知有沒有錯。
我原來的想法是以為你並「沒有」把演算法拆成二部份。剛又再細看,感覺上你有拆了,所以是誤會。

請問一下,開二個thread,然後用SetThreadAffinityMask不是就是將這二個thread指定到這二個核心上嗎?因為這樣指定後cpu使用率變成70~80%了,但時間卻沒什麼變,這點我最覺的奇怪。
時間卻沒什麼變,關於這點,大概就是如我說的原本windows就會去使用雙核/cpu的所有資源,假設你增加成多核後,windows不懂的如何去運用它,那硬體變強不就沒意義了? 所以windows是一定會知道要怎麼去把多核使用到"較佳"的狀態。如果說一個核100%的跑,與二個核各自少跑一點,若真的會有很大的差異出來。那大概就是windows的調配真的很差很差! 結論: 你說時間卻沒什麼變,是不是因為這樣?

我是這樣子做的沒錯,如四核心則拆成四分,quad的方式來處理各別的資料,最後用waitformultiobjects來做結束
嗯!

就是用SetThreadAffinityMask來指定的
嗯!

應該是指waitformultiobjects嗎??
嗯!

所以您的意思是指用「tbitmap」就是vcl嗎?
是!

請問這個「TBmp->Canvas->Lock」的部份是加在for的下方嗎?還是加在那邊,因為我加在for的下方,時間還是比單thread的二倍久,而只加在newbmp的部份,時間還是比較久,但是比for的下面時間要快,是我加錯地方嗎?
這部份僅針對要被「寫入」的那個bmp,純讀的那二個不需要。而加入的位置則是加在「寫入前」,與「寫完」後。

所以我拆成二個thread的做法有缺失,仍然還是用main thread在處理的意思嗎,所以才會造成二倍時間的關係。
如果你用了synchronize的話,是的,還是main thread在跑。所以『不要用synchoronize這個方法!!!』

以上。

請問因為我問別人,他們也是說只要將圖片拆解,然後寫入即可增加計算速度,所以我才會用這種方式來處理,他們是用vc 寫的,還是因為我對delphi的觀念有問題,所以才無法增加速度?
關於這點我上面有講到。我個人認為windows對於多核/cpu的運用應該是不會很差才是。也就是說它理論上知道如何把工作配給不同的核/ cpu。當然,這方面我沒實測過,不了解是否真的可以透過自己的「調用cpu」來提高效能。題外話,如果說把拆開的工作交給另外一台電腦的話理論上會有幫助,但前題也要是該工作真的對一台電腦來說要算超久的。


>> 最多把該thread的 priority 拉到最高再用SetThreadAffinityMask恉定該thread至另一個核上。
>>請問藍字的地方,是指說還是用二個thread的方式來處理嗎?不是很能了解這段話的意義。
我是指
不用拆解演算,把「一個問題」「全然的」交給一個new 出一個thread來處理。也就是main form 1條 thread。但該thread指定到另一核/cpu上 (即與main form用的是不同的核)







------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#15 引用回覆 回覆 發表時間:2011-07-26 11:23:24 IP:219.87.xxx.xxx 訂閱
=================== aftcast ===================
你的說法是正確的。但多數人使用multithread的原因並不是把「一個」工作「切成n個」並運用multithread處理。因為並行運算也有可能把工作切到不同的電腦上來算。

可是請問一下,因為雙核cpu沒有達到100%,所以才將一個工作切成n個,這樣才可以完全利用到cpu,以減少計算時間,當初的想法是這樣

時間卻沒什麼變,關於這點,大概就是如我說的原本windows就會去使用雙核/cpu的所有資源,假設你增加成多核後,windows不懂的如何去運用它,那硬體變強不就沒意義了? 所以windows是一定會知道要怎麼去把多核使用到"較佳"的狀態。如果說一個核100%的跑,與二個核各自少跑一點,若真的會有很大的差異出來。那大概就是windows的調配真的很差很差! 結論: 你說時間卻沒什麼變,是不是因為這樣?
關於這點就是我提出問題的地方,理論上,使用強制分配threadcpu上應該可以造成雙核cpu執行達100%的效果(先不管時間的問題),但卻不知是那邊的問題導致無法提昇效能

所以您的意思是指用「tbitmap」就是vcl?
!
所以vcl並不是指有介面的程式才是vcl囉,那是指只要是class都是vcl?(delphi),不好意思問了很笨的問題。

這部份僅針對要被「寫入」的那個bmp,純讀的那二個不需要。而加入的位置則是加在「寫入前」,與「寫完」後。
試過只在[寫入]的部份加上tbmp.canvas.lock/ tbmp.canvas.unlock時間還是成二倍,如果只用mainthread來執行時間卻比較快(cpu卻只有50%),真的搞不懂為什麼了…

以上。

關於這點我上面有講到。我個人認為windows對於多核/cpu的運用應該是不會很差才是。也就是說它理論上知道如何把工作配給不同的核/ cpu。當然,這方面我沒實測過,不了解是否真的可以透過自己的「調用cpu」來提高效能。題外話,如果說把拆開的工作交給另外一台電腦的話理論上會有幫助,但前題也要是該工作真的對一台電腦來說要算超久的。
當初會有這種想法,因為c 有提供openmp這種東西,而delphi沒有,所以去google查了,找到一個多核計算的範例,其內容是同一段程式碼用雙核中的單核跑二次,與雙核分別各跑一次,時間差了快一倍,所以才會想在這邊做這種方式來減少時間。

我是指不用拆解演算,把「一個問題」「全然的」交給一個new 出一個thread來處理。也就是main form 1 thread。但該thread指定到另一核/cpu (即與main form用的是不同的核)
意思是指用mainthread 1thread=2thread各自在單核上面執行的意思嗎?還是指計算都給new出來的那個thread來執行,那mainthread就做waitforsingleobject的等待嗎??如有理解錯誤的地方請再麻煩告知,小弟先來試試看
------
DELPHI初學者
jcjroc
高階會員


發表:21
回覆:276
積分:114
註冊:2002-09-18

發送簡訊給我
#16 引用回覆 回覆 發表時間:2011-07-26 12:36:31 IP:211.23.xxx.xxx 訂閱
喔!!!那就是不牽涉UI啦
那把BCB(VCL)暫時丟到牆角去吧!!
有VC(MFC)的話一起!!!

就用前兩條 CreateCompatibleDC SelectObject,DeleteObject,CreateDIBSection
其實前兩條就夠了............但對那個答案,我基本上很懶,所以就拿來用啦!!!


你的問題用多執行緒一次同時處理多組來源也都OK!!!因為都是獨立的,所以跟同步一點關係都沒有!!!

根據發問需求.....這是最精簡而Powerful的解決方案,但最關鍵的前提是必須熟悉BMP格式.


VCL&MFC&QT....都是好東西,但前提是使用者基礎要好,不然在我看來會是累贅..................害人喔!!!

===================引 用 macchen 文 章===================
不好意思,不是很懂呢??答案是什麼?可以再指導小弟一下嗎?不好意思,真的不是很懂你在說什麼呢,謝謝你的回覆。

給你個方向吧!!!
1.去用力地啃一下BMP的格式!!
??格式有什麼特別嗎??
2.如果圖形來源是檔案,那再瞄一下CreateFile,CreateFileMapping,MapViewOfFile.
為什麼要用這三個??
3.如果還要顯示比對(運算)後的結果,那再蹬一眼CreateWindow,GetDC,SelectObject,DeleteObject,CreateDIBSection
我只是要用運算比對資料,你這幾個會用的到嗎??不是很了解,麻煩再告知一下。
4.如果第3點成立,嗯!!來點酷一點的,青一眼InvalidateRect
我沒有要繪圖?為什麼會用到這個??
5.啥!!這還不夠炫,還要再加上zoom in跟zoom out........那含著眼淚再看看
SetMapMode,SetWindowExtEx,SetViewportExtEx.

===================引 用 jcjroc 文 章===================
答案不是給你了嗎????
編輯記錄
jcjroc 重新編輯於 2011-07-25 22:41:03, 註解 無‧
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#17 引用回覆 回覆 發表時間:2011-07-26 15:47:31 IP:112.104.xxx.xxx 未訂閱
jcjroc 大大的意思是直接針對檔案內含值做比較...

以下測試碼提供你參考

// BITMAP檔案格式:
// http://crazycat1130.pixnet.net/blog/post/1345538

[code delphi]
unit fMain;

interface


uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;


type

{ TMyBitmap }
TMyBitmap = class(TPersistent)
private
FFileName: string;
FStream: TMemoryStream;
function GetScanLineCount: Integer;
function GetScanLineLength: Integer;
function GetScanLines(Index: Integer): PByte;
function GetFileHeader: PBitmapFileHeader;
function GetInfoHeader: PBitmapInfoHeader;
protected
function _ptr(p: Pointer; offset: Integer): Pointer;
procedure LoadFromFile(FileName: string); virtual;
property FileName: string read FFileName;
property Stream: TMemoryStream read FStream;
property FileHeader: PBitmapFileHeader read GetFileHeader;
property InfoHeader: PBitmapInfoHeader read GetInfoHeader;
property ScanLineCount: Integer read GetScanLineCount;
property ScanLineLength: Integer read GetScanLineLength;
property ScanLines[Index: Integer]: PByte read GetScanLines; default;
public
constructor Create(FileName: string); virtual;
destructor Destroy; override;
function BitmapFileHeaderText: string;
function BitmapInfoHeaderText: string;
end;


{ TForm1 }
TfrmMain = class(TForm)
Button1: TButton;
ListBox1: TListBox;
ListBox2: TListBox;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
public
end;


var
frmMain: TfrmMain;


implementation


{$R *.dfm}


{ TMyBitmap }


function TMyBitmap._ptr(p: Pointer; offset: Integer): Pointer;
begin
Result := Pointer(Integer(p) offset);
end;


constructor TMyBitmap.Create(FileName: string);
begin
inherited Create;
FFileName := '';
FStream := nil;
LoadFromFile(FileName);
end;


destructor TMyBitmap.Destroy;
begin
FreeAndNil(FStream);
inherited;
end;


function TMyBitmap.GetFileHeader: PBitmapFileHeader;
begin
if FStream=nil
then Result := nil
else Result := PBitmapFileHeader(FStream.Memory);
end;


function TMyBitmap.GetInfoHeader: PBitmapInfoHeader;
begin
if FStream=nil
then Result := nil
else Result := PBitmapInfoHeader(_ptr(FStream.Memory,$E));
end;


function TMyBitmap.GetScanLines(Index: Integer): PByte;
begin
if(FileHeader=nil) or (InfoHeader=nil) or
(Index<0) or (Index>InfoHeader.biHeight) then
begin
Result := nil;
end
else begin
with FStream,FileHeader^,InfoHeader^ do
Result := _ptr(Memory,
Integer(bfOffBits) GetScanLineLength*Index);
end;
end;


function TMyBitmap.GetScanLineCount: Integer;
begin
if InfoHeader=nil
then Result := 0
else Result := InfoHeader.biHeight;
end;


function TMyBitmap.GetScanLineLength: Integer;
begin
if (FileHeader=nil) or (InfoHeader=nil) then Result := 0
else begin
with FileHeader^,InfoHeader^ do
Result := Integer(bfSize-bfOffBits) div biHeight;
end;
end;


procedure TMyBitmap.LoadFromFile(FileName: string);
begin
if FileExists(FileName) then
begin
FFileName := FileName;
FreeAndNil(FStream);
FStream := TMemoryStream.Create;
FStream.LoadFromFile(FFileName);
end;
end;


function TMyBitmap.BitmapFileHeaderText: string;
var
L: TStringList;
begin
Result := 'Invalidate BitmapFileHeader';
if FileHeader=nil then EXIT;
L := TStringList.Create;
try
with FileHeader^ do
begin
L.Add(Format('bfType=%s%s',[
AnsiChar(Lo(bfType)),
AnsiChar(Hi(bfType))]));


L.Add(Format('bfSize=%d',[bfSize]));
L.Add(Format('bfReserved1=%d',[bfReserved1]));
L.Add(Format('bfReserved2=%d',[bfReserved2]));
L.Add(Format('bfOffBits=%d',[bfOffBits]));
end;
Result := L.Text;
finally
FreeAndNil(L);
end;
end;


function TMyBitmap.BitmapInfoHeaderText: string;
var
L: TStringList;
begin
Result := 'Invalidate BitmapInfoHeader';
if InfoHeader=nil then EXIT;


L := TStringList.Create;
try
with InfoHeader^ do
begin
L.Add(Format('biSize=%d',[biSize]));
L.Add(Format('Width=%d',[biWidth]));
L.Add(Format('Height=%d',[biHeight]));
L.Add(Format('Planes=%d',[biPlanes]));
L.Add(Format('BitCount=%d',[biBitCount]));
L.Add(Format('Compression=%d',[biCompression]));
L.Add(Format('SizeImage=%d',[biSizeImage]));
L.Add(Format('XPelsPerMeter=%d',[biXPelsPerMeter]));
L.Add(Format('YPelsPerMeter=%d',[biYPelsPerMeter]));
L.Add(Format('ClrUsed=%d',[biClrUsed]));
L.Add(Format('biClrImportant=%d',[biClrImportant]));
L.Add('');
L.Add(Format('GetScanLineCount=%d',[GetScanLineCount]));
L.Add(Format('GetScanLineLength=%d',[GetScanLineLength]));
end;
Result := L.Text;
finally
FreeAndNil(L);
end;
end;


{ TfrmMain }


procedure TfrmMain.Button1Click(Sender: TObject);
var
O: TMyBitmap;
begin
if FileExists('D:\TEST.BMP') then
begin
O := TMyBitmap.Create('D:\TEST.BMP');
try
ListBox1.Items.Text := O.BitmapFileHeaderText;
ListBox2.Items.Text := O.BitmapInfoHeaderText;
finally
FreeAndNil(O);
end;
end;
end;


procedure TfrmMain.Button2Click(Sender: TObject);
var
I,Count: Integer;
M: TMemoryStream;
O: TMyBitmap;
begin
if FileExists('D:\TEST.BMP') then
begin
O := TMyBitmap.Create('D:\TEST.BMP');
try
M := TMemoryStream.Create;
try
M.Write(O.FileHeader^,SizeOf(TBitmapFileHeader));
M.Write(O.InfoHeader^,SizeOf(TBitmapInfoHeader));
Count := O.ScanLineCount;
//反轉圖形測試(uses ScanLines)
for I := 0 to Count-1 do
M.Write(O[Count-I-1]^,O.GetScanLineLength);
M.SaveToFile('D:\TEST_2.BMP');
finally
FreeAndNil(M);
end;
finally
FreeAndNil(O);
end;
end;
end;


end.
[/code]

謹供參考 ... ^_^
編輯記錄
jow 重新編輯於 2011-07-26 01:56:07, 註解 無‧
macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#18 引用回覆 回覆 發表時間:2011-07-26 17:05:04 IP:219.87.xxx.xxx 訂閱
恕刪,請問一下,是指我的方式所以造成速度變嗎?還是指我的作法有問題,因為我作圖形的比對,是整張圖每一個值都要抓出來比較,不是只做xor,而是要依據其中一張圖片的值來產生新的圖片,所以想請問一下,是我的方法錯了嗎?您附上的程式碼用意什麼,可以指點一下小弟,我有點不懂意思了,謝謝你的回覆。

===================引 用 jow 文 章===================
jcjroc大大的意思是直接針對檔案內含值做比較...


------
DELPHI初學者
jcjroc
高階會員


發表:21
回覆:276
積分:114
註冊:2002-09-18

發送簡訊給我
#19 引用回覆 回覆 發表時間:2011-07-26 19:01:34 IP:211.23.xxx.xxx 訂閱
是這樣沒錯,但我採用記憶體映射,效能比你的方式還要好很多.程式也單純多多.(我是懶惰鬼,我的字典裡找不到"勤勞"兩個字)
===================引 用 jow 文 章===================
jcjroc大大的意思是直接針對檔案內含值做比較...

以下測試碼提供你參考

// BITMAP檔案格式:
// http://crazycat1130.pixnet.net/blog/post/1345538

[code delphi]
unit fMain;

interface


uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;


type

{ TMyBitmap }
TMyBitmap = class(TPersistent)
private
FFileName: string;
FStream: TMemoryStream;
function GetScanLineCount: Integer;
function GetScanLineLength: Integer;
function GetScanLines(Index: Integer): PByte;
function GetFileHeader: PBitmapFileHeader;
function GetInfoHeader: PBitmapInfoHeader;
protected
function _ptr(p: Pointer; offset: Integer): Pointer;
procedure LoadFromFile(FileName: string); virtual;
property FileName: string read FFileName;
property Stream: TMemoryStream read FStream;
property FileHeader: PBitmapFileHeader read GetFileHeader;
property InfoHeader: PBitmapInfoHeader read GetInfoHeader;
property ScanLineCount: Integer read GetScanLineCount;
property ScanLineLength: Integer read GetScanLineLength;
property ScanLines[Index: Integer]: PByte read GetScanLines; default;
public
constructor Create(FileName: string); virtual;
destructor Destroy; override;
function BitmapFileHeaderText: string;
function BitmapInfoHeaderText: string;
end;


{ TForm1 }
TfrmMain = class(TForm)
Button1: TButton;
ListBox1: TListBox;
ListBox2: TListBox;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
public
end;


var
frmMain: TfrmMain;


implementation


{$R *.dfm}


{ TMyBitmap }


function TMyBitmap._ptr(p: Pointer; offset: Integer): Pointer;
begin
Result := Pointer(Integer(p) offset);
end;


constructor TMyBitmap.Create(FileName: string);
begin
inherited Create;
FFileName := '';
FStream := nil;
LoadFromFile(FileName);
end;


destructor TMyBitmap.Destroy;
begin
FreeAndNil(FStream);
inherited;
end;


function TMyBitmap.GetFileHeader: PBitmapFileHeader;
begin
if FStream=nil
then Result := nil
else Result := PBitmapFileHeader(FStream.Memory);
end;


function TMyBitmap.GetInfoHeader: PBitmapInfoHeader;
begin
if FStream=nil
then Result := nil
else Result := PBitmapInfoHeader(_ptr(FStream.Memory,$E));
end;


function TMyBitmap.GetScanLines(Index: Integer): PByte;
begin
if(FileHeader=nil) or (InfoHeader=nil) or
(Index<0) or (Index>InfoHeader.biHeight) then
begin
Result := nil;
end
else begin
with FStream,FileHeader^,InfoHeader^ do
Result := _ptr(Memory,
Integer(bfOffBits) GetScanLineLength*Index);
end;
end;


function TMyBitmap.GetScanLineCount: Integer;
begin
if InfoHeader=nil
then Result := 0
else Result := InfoHeader.biHeight;
end;


function TMyBitmap.GetScanLineLength: Integer;
begin
if (FileHeader=nil) or (InfoHeader=nil) then Result := 0
else begin
with FileHeader^,InfoHeader^ do
Result := Integer(bfSize-bfOffBits) div biHeight;
end;
end;


procedure TMyBitmap.LoadFromFile(FileName: string);
begin
if FileExists(FileName) then
begin
FFileName := FileName;
FreeAndNil(FStream);
FStream := TMemoryStream.Create;
FStream.LoadFromFile(FFileName);
end;
end;


function TMyBitmap.BitmapFileHeaderText: string;
var
L: TStringList;
begin
Result := 'Invalidate BitmapFileHeader';
if FileHeader=nil then EXIT;
L := TStringList.Create;
try
with FileHeader^ do
begin
L.Add(Format('bfType=%s%s',[
AnsiChar(Lo(bfType)),
AnsiChar(Hi(bfType))]));


L.Add(Format('bfSize=%d',[bfSize]));
L.Add(Format('bfReserved1=%d',[bfReserved1]));
L.Add(Format('bfReserved2=%d',[bfReserved2]));
L.Add(Format('bfOffBits=%d',[bfOffBits]));
end;
Result := L.Text;
finally
FreeAndNil(L);
end;
end;


function TMyBitmap.BitmapInfoHeaderText: string;
var
L: TStringList;
begin
Result := 'Invalidate BitmapInfoHeader';
if InfoHeader=nil then EXIT;


L := TStringList.Create;
try
with InfoHeader^ do
begin
L.Add(Format('biSize=%d',[biSize]));
L.Add(Format('Width=%d',[biWidth]));
L.Add(Format('Height=%d',[biHeight]));
L.Add(Format('Planes=%d',[biPlanes]));
L.Add(Format('BitCount=%d',[biBitCount]));
L.Add(Format('Compression=%d',[biCompression]));
L.Add(Format('SizeImage=%d',[biSizeImage]));
L.Add(Format('XPelsPerMeter=%d',[biXPelsPerMeter]));
L.Add(Format('YPelsPerMeter=%d',[biYPelsPerMeter]));
L.Add(Format('ClrUsed=%d',[biClrUsed]));
L.Add(Format('biClrImportant=%d',[biClrImportant]));
L.Add('');
L.Add(Format('GetScanLineCount=%d',[GetScanLineCount]));
L.Add(Format('GetScanLineLength=%d',[GetScanLineLength]));
end;
Result := L.Text;
finally
FreeAndNil(L);
end;
end;


{ TfrmMain }


procedure TfrmMain.Button1Click(Sender: TObject);
var
O: TMyBitmap;
begin
if FileExists('D:\TEST.BMP') then
begin
O := TMyBitmap.Create('D:\TEST.BMP');
try
ListBox1.Items.Text := O.BitmapFileHeaderText;
ListBox2.Items.Text := O.BitmapInfoHeaderText;
finally
FreeAndNil(O);
end;
end;
end;


procedure TfrmMain.Button2Click(Sender: TObject);
var
I,Count: Integer;
M: TMemoryStream;
O: TMyBitmap;
begin
if FileExists('D:\TEST.BMP') then
begin
O := TMyBitmap.Create('D:\TEST.BMP');
try
M := TMemoryStream.Create;
try
M.Write(O.FileHeader^,SizeOf(TBitmapFileHeader));
M.Write(O.InfoHeader^,SizeOf(TBitmapInfoHeader));
Count := O.ScanLineCount;
//反轉圖形測試(uses ScanLines)
for I := 0 to Count-1 do
M.Write(O[Count-I-1]^,O.GetScanLineLength);
M.SaveToFile('D:\TEST_2.BMP');
finally
FreeAndNil(M);
end;
finally
FreeAndNil(O);
end;
end;
end;


end.
[/code]

謹供參考 ... ^_^
編輯記錄
jcjroc 重新編輯於 2011-07-26 05:12:07, 註解 無‧
jcjroc 重新編輯於 2011-07-26 05:14:13, 註解 無‧
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#20 引用回覆 回覆 發表時間:2011-07-26 19:14:05 IP:210.64.xxx.xxx 訂閱
哇,好熱鬧,大概是這問題算有些水準吧… 續繼來插花一下:

TO: jcjroc


>>就用前兩條 CreateCompatibleDC SelectObject,DeleteObject,CreateDIBSection
>>其實前兩條就夠了............但對那個答案,我基本上很懶,所以就拿來用啦!!!

根據你一開始講的五點,我怎覺得好像認識你? 你是jack 張?
不過我覺得這提問者的問題應該不至於需要用到那麼多的技巧。如 CreateFileMapping,MapViewOfFile 這類的…
如果眞的需要加速的話,應該是照jow的方式,不需要管DC與bmp的任何api。只管把檔案讀入記憶體中即可。

To Jow :
每次看你回覆都好用心,而且也常提供解答的範例,而且答案都很正確,真讓我配服。
針對這次的問題,我最好奇的是二條thread分別在不同的core上是否真的可以提高效能,而非TBitmap的封裝後造成變慢(當然這也是會)。你覺得呢?

To machhen:

上面二位先進的講的都是運用較低階的方式來做比對。這樣的做法是可以提昇一些效能,尤其是如果把bmp整個讀入記憶體中,純靠指標在裡面取出互比。 jow 的範例就是在講那個 。 如此的做法就不管DC也因此不用管同步(理論上你每個寫入目標的記憶體位址不會是同一個)。你可以試著去了解一下。而要了解的前題就是知道bmp檔案的結構,即bmp的檔頭資訊與bmp的pixel內容。然後把檔案用一般的方式讀入.。

你原來的方法沒有錯。最多只能說用TBitmap的物件與方法會比較慢一點點。但是否用二條thread就可以增快,這是我比較想知道的,也想再研究的。但手上目前沒有例子可以做…

===================引 用 macchen 文 章===================
恕刪,請問一下,是指我的方式所以造成速度變嗎?還是指我的作法有問題,因為我作圖形的比對,是整張圖每一個值都要抓出來比較,不是只做xor,而是要依據其中一張圖片的值來產生新的圖片,所以想請問一下,是我的方法錯了嗎?您附上的程式碼用意什麼,可以指點一下小弟,我有點不懂意思了,謝謝你的回覆。

------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
jcjroc
高階會員


發表:21
回覆:276
積分:114
註冊:2002-09-18

發送簡訊給我
#21 引用回覆 回覆 發表時間:2011-07-26 19:50:00 IP:211.23.xxx.xxx 訂閱
效能.......一組一千組一萬組 0.5s 500s 5000s .............再加幾顆CPU,然後多泡幾杯咖啡,如此之差而已.
加油啦!!!!
===================引 用 aftcast 文 章===================
哇,好熱鬧,大概是這問題算有些水準吧… 續繼來插花一下:

TO: jcjroc


>>就用前兩條 CreateCompatibleDC SelectObject,DeleteObject,CreateDIBSection
>>其實前兩條就夠了............但對那個答案,我基本上很懶,所以就拿來用啦!!!

根據你一開始講的五點,我怎覺得好像認識你? 你是jack 張?
不過我覺得這提問者的問題應該不至於需要用到那麼多的技巧。如 CreateFileMapping,MapViewOfFile 這類的…
如果眞的需要加速的話,應該是照jow的方式,不需要管DC與bmp的任何api。只管把檔案讀入記憶體中即可。

To Jow :
每次看你回覆都好用心,而且也常提供解答的範例,而且答案都很正確,真讓我配服。
針對這次的問題,我最好奇的是二條thread分別在不同的core上是否真的可以提高效能,而非TBitmap的封裝後造成變慢(當然這也是會)。你覺得呢?

To machhen:

上面二位先進的講的都是運用較低階的方式來做比對。這樣的做法是可以提昇一些效能,尤其是如果把bmp整個讀入記憶體中,純靠指標在裡面取出互比。 jow 的範例就是在講那個 。 如此的做法就不管DC也因此不用管同步(理論上你每個寫入目標的記憶體位址不會是同一個)。你可以試著去了解一下。而要了解的前題就是知道bmp檔案的結構,即bmp的檔頭資訊與bmp的pixel內容。然後把檔案用一般的方式讀入.。

你原來的方法沒有錯。最多只能說用TBitmap的物件與方法會比較慢一點點。但是否用二條thread就可以增快,這是我比較想知道的,也想再研究的。但手上目前沒有例子可以做…

===================引 用 macchen 文 章===================
恕刪,請問一下,是指我的方式所以造成速度變嗎?還是指我的作法有問題,因為我作圖形的比對,是整張圖每一個值都要抓出來比較,不是只做xor,而是要依據其中一張圖片的值來產生新的圖片,所以想請問一下,是我的方法錯了嗎?您附上的程式碼用意什麼,可以指點一下小弟,我有點不懂意思了,謝謝你的回覆。

aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#22 引用回覆 回覆 發表時間:2011-07-26 20:31:16 IP:210.64.xxx.xxx 訂閱
回 macchen 上面的問題:

1/ VCL 用另一種簡單的方式講就是 delphi 裡所提供的元件,無論是可視或不可視或可不可以在設計時期拉進來,通通可以當它是VCL元件。(不精準的說法,但差不多那樣想就可以)

2/ 你說「如果只用mainthread來執行時間卻比較快」。而且快近二倍。那是否表示…問題在同步? 再問一下,若thread裡不用synchronize,也不用lock,那情形如何? 一樣差了近二倍嗎?

3/ [ 當初會有這種想法,因為c 有提供openmp這種東西,而delphi沒有,所以去google查了,找到一個多核計算的範例,其內容是同一段程式碼用雙核中的單核跑二次,與雙核分別各跑一次,時間差了快一倍,所以才會想在這邊做這種方式來減少時間。]
我想找時間也去研究一下,有心得在和你分享一下。

4 mainform 本身就是一條thread,即mainthread。我指的是new一個thead,然後把計算都給new出來的那個用,但指定此new出來的thread至另一核上 (非mainform上的那個核)

5 若照我上面4的做法。那就不用waitforsingleobject。mainform也不能這樣做!!!。你只要在new出來的thread的excute的最後一行sendmessage 給 mainform 通知一下就可以。但建議目前測速的情形下,用MessageBox這個api來show一下,就表示結束。如此測時間方便一點。若確定合你要的,再去設剛講的message (這要自訂一個message)。
------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#23 引用回覆 回覆 發表時間:2011-07-27 00:15:52 IP:123.193.xxx.xxx 未訂閱
再提供一個沒有資料封裝的版本, 
僅提供個人對於資料處理的看法,無關平行運算
謹供參考 ^_^

[code delphi]
procedure TfrmMain.Button10Click(Sender: TObject);
var
M: TMemoryStream;
fh: PBitmapFileHeader;
ih: PBitmapInfoHeader;
p1,p2,tt: PByte;
size: Integer;
Label DO_EXIT;
begin
if not FileExists('D:\TEST.BMP') then EXIT;

M := TMemoryStream.Create;
try
M.LoadFromFile('D:\TEST.BMP');
fh := M.Memory;
ih := Pointer(Integer(fh) SizeOf(fh^));
//限定 Bitmap 格式...
if (fh=nil) or (PWORD(fh)^<>$4D42) then goto DO_EXIT;
if (ih=nil) or (ih.biBitCount<>24) then goto DO_EXIT;

with fh^,ih^ do
begin
size := Integer(bfSize-bfOffBits) div biHeight;
GetMem(tt,size);
try
//pointer of Bitmap Data
p1 := Pointer(Integer(fh) Integer(bfOffBits));
p2 := Pointer(Integer(p1) size*(biHeight-1));
repeat
Move(p2^,tt^,size);
Move(p1^,p2^,size);
Move(tt^,p1^,size);
Inc(p1,size);
Dec(p2,size);
until Integer(p1)>=Integer(p2);
M.SaveToFile('D:\TEST_2.BMP');
finally
FreeMem(tt,size);
end;
end;

DO_EXIT:
finally
FreeAndNil(M);
end;
end;

[/code]


macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#24 引用回覆 回覆 發表時間:2011-07-27 09:07:36 IP:219.87.xxx.xxx 訂閱
抱歉下面太多恕刪。
謝謝你的回覆,想請問 一下所謂用「記憶體映射」的方式是指記憶體移動嗎?還是指「MapViewOfFile」,這個不是只是用來處理不同程序間資料溝通用的嗎??
另外問一下,採用jow大大的程式碼,就算我的圖是pf1bit而且是每一個bit都要處理,速度也是很快嗎?因為這個程式碼第一次看過,自已也沒寫過這種,所以不是很了解,加上上班又在忙別的事
更不能專心看文,但還是感謝您的回文。
===================引 用 jcjroc 文 章===================
是這樣沒錯,但我採用記憶體映射,效能比你的方式還要好很多.程式也單純多多.(我是懶惰鬼,我的字典裡找不到"勤勞"兩個字)
------
DELPHI初學者
macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#25 引用回覆 回覆 發表時間:2011-07-27 09:12:40 IP:219.87.xxx.xxx 訂閱
感謝aftcast大大的回覆,觀念問題真是很難搞,但一定要先了解,才能處理。
===================引 用 aftcast 文 章===================
回 macchen 上面的問題:

1/ VCL 用另一種簡單的方式講就是 delphi 裡所提供的元件,無論是可視或不可視或可不可以在設計時期拉進來,通通可以當它是VCL元件。(不精準的說法,但差不多那樣想就可以)
嗯,我了解了。

2/ 你說「如果只用mainthread來執行時間卻比較快」。而且快近二倍。那是否表示…問題在同步? 再問一下,若thread裡不用synchronize,也不用lock,那情形如何? 一樣差了近二倍嗎?
一開始就是沒加synchronize及lock的方式,就是一樣很慢,是差二倍時間沒錯,所以才會想說是不是vcl的關系,但沒想到其他的大大提出了別種方式,可以更快,但是我還沒測試。

3/ [ 當初會有這種想法,因為c 有提供openmp這種東西,而delphi沒有,所以去google查了,找到一個多核計算的範例,其內容是同一段程式碼用雙核中的單核跑二次,與雙核分別各跑一次,時間差了快一倍,所以才會想在這邊做這種方式來減少時間。]
我想找時間也去研究一下,有心得在和你分享一下。
非常感謝您花時間了解這個問題。

4 mainform 本身就是一條thread,即mainthread。我指的是new一個thead,然後把計算都給new出來的那個用,但指定此new出來的thread至另一核上 (非mainform上的那個核)
嗯,了解。

5 若照我上面4的做法。那就不用waitforsingleobject。mainform也不能這樣做!!!。你只要在new出來的thread的excute的最後一行sendmessage 給 mainform 通知一下就可以。但建議目前測速的情形下,用MessageBox這個api來show一下,就表示結束。如此測時間方便一點。若確定合你要的,再去設剛講的message (這要自訂一個message)。
嗯,應該用一個message來處理即可。
------
DELPHI初學者
macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#26 引用回覆 回覆 發表時間:2011-07-27 09:14:29 IP:219.87.xxx.xxx 訂閱
抱歉恕刪。
感謝jcjroc大大的回覆,這個時間是呈線性的嗎?這樣還真的很快,非常感謝您提供的觀念,小弟不是很了解,但會再花時間看完jow提供的代碼。
===================引 用 jcjroc 文 章===================
效能.......一組一千組一萬組 0.5s 500s 5000s .............再加幾顆CPU,然後多泡幾杯咖啡,如此之差而已.
加油啦!!!!
------
DELPHI初學者
macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#27 引用回覆 回覆 發表時間:2011-07-27 09:20:04 IP:219.87.xxx.xxx 訂閱
抱歉,恕刪。
非常感謝jow大大的程式碼,花時間打這些code應該手會很酸吧,想請問一下,我這個圖片是pf1bit,所以我需要1個1個bit去處理,用您提供的程式碼也行嗎,最近公事又在忙了,所以想先請教一下觀念,不是直接做xor,因為要
依據其中一張圖來決定是否要填入1的值,請問是在「Move(p2^,tt^,size);」這段做處理即可嗎?非常謝謝您的代碼,話說,新的代碼真的省很多了,也比較好理解,但我還是會將這二個代碼努力的啃一下,如有任何問題再請jow指
導一下小弟,畢竟沒碰過的東西實在太多了,謝謝。
===================引 用 jow 文 章===================
再提供一個沒有資料封裝的版本,
僅提供個人對於資料處理的看法,無關平行運算
謹供參考 ^_^

[code delphi]
procedure TfrmMain.Button10Click(Sender: TObject);
var
M: TMemoryStream;
fh: PBitmapFileHeader;
ih: PBitmapInfoHeader;
p1,p2,tt: PByte;
size: Integer;
Label DO_EXIT;
begin
if not FileExists('D:\TEST.BMP') then EXIT;

M := TMemoryStream.Create;
try
M.LoadFromFile('D:\TEST.BMP');
fh := M.Memory;
ih := Pointer(Integer(fh) SizeOf(fh^));
//限定 Bitmap 格式...
if (fh=nil) or (PWORD(fh)^<>$4D42) then goto DO_EXIT;
if (ih=nil) or (ih.biBitCount<>24) then goto DO_EXIT;

with fh^,ih^ do
begin
size := Integer(bfSize-bfOffBits) div biHeight;
GetMem(tt,size);
try
//pointer of Bitmap Data
p1 := Pointer(Integer(fh) Integer(bfOffBits));
p2 := Pointer(Integer(p1) size*(biHeight-1));
repeat
Move(p2^,tt^,size);
Move(p1^,p2^,size);
Move(tt^,p1^,size);
Inc(p1,size);
Dec(p2,size);
until Integer(p1)>=Integer(p2);
M.SaveToFile('D:\TEST_2.BMP');
finally
FreeMem(tt,size);
end;
end;

DO_EXIT:
finally
FreeAndNil(M);
end;
end;

[/code]


------
DELPHI初學者
jcjroc
高階會員


發表:21
回覆:276
積分:114
註冊:2002-09-18

發送簡訊給我
#28 引用回覆 回覆 發表時間:2011-07-27 12:37:44 IP:211.23.xxx.xxx 訂閱
你可能會錯意了!!!
我是在跟你說,錯誤的觀念 錯誤的邏輯 錯誤的技術引用是經不起實際商業運用的考驗........不過Demo的話,隨便就好.........

給台車給舒馬克開,他絕對大腳一踩油門到底........阿!!啥極速才90公里喔!!!舒馬克夠爛.........還號稱是車神.......
給台法拉利讓我開........看我神氣坐上駕駛座發動引擎......大腳一踩油門到底........阿!!啥極速才60公里喔!!!法拉利夠爛.........還號稱是超級跑車.......
===================引 用 macchen 文 章===================
抱歉恕刪。
感謝jcjroc大大的回覆,這個時間是呈線性的嗎?這樣還真的很快,非常感謝您提供的觀念,小弟不是很了解,但會再花時間看完jow提供的代碼。
===================引 用 jcjroc 文 章===================
效能.......一組一千組一萬組 0.5s 500s 5000s .............再加幾顆CPU,然後多泡幾杯咖啡,如此之差而已.
加油啦!!!!
macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#29 引用回覆 回覆 發表時間:2011-07-27 13:35:27 IP:219.87.xxx.xxx 訂閱
jcjroc大大你好,可以請說的白話一點嗎?每次都搞不太懂你的意思,謝謝。
===================引 用 jcjroc 文 章===================
你可能會錯意了!!!
我是在跟你說,錯誤的觀念 錯誤的邏輯 錯誤的技術引用是經不起實際商業運用的考驗........不過Demo的話,隨便就好.........

給台車給舒馬克開,他絕對大腳一踩油門到底........阿!!啥極速才90公里喔!!!舒馬克夠爛.........還號稱是車神.......
給台法拉利讓我開........看我神氣坐上駕駛座發動引擎......大腳一踩油門到底........阿!!啥極速才60公里喔!!!法拉利夠爛.........還號稱是超級跑車.......
------
DELPHI初學者
jcjroc
高階會員


發表:21
回覆:276
積分:114
註冊:2002-09-18

發送簡訊給我
#30 引用回覆 回覆 發表時間:2011-07-27 13:53:01 IP:211.23.xxx.xxx 訂閱
舒馬克當然是車神...........極速90是因為給他的車是台20幾年前的裕隆速利1200
法拉利當然是超級跑車...........問題是我不知道要換檔......................

以上的共通點是......裕隆速利是我給舒馬克的................法拉利是我開的..........
結論是不管法拉利或是舒馬克都很爛............而我是最好的............

程式跑不快...........是硬體還是軟體關係?????阿災............反正這時候我是路人甲買醬油路過的.......

題外話........如果你的題目是我做的話,依需求,對我來說會趨近線性沒錯.

jow:根據需求然後只使用單執行緒,如果我來弄至少會快你4倍,相信你會知道原因的.但只是Demo而已隨便就好.

===================引 用 macchen 文 章===================
jcjroc大大你好,可以請說的白話一點嗎?每次都搞不太懂你的意思,謝謝。
===================引 用 jcjroc 文 章===================
你可能會錯意了!!!
我是在跟你說,錯誤的觀念 錯誤的邏輯 錯誤的技術引用是經不起實際商業運用的考驗........不過Demo的話,隨便就好.........

給台車給舒馬克開,他絕對大腳一踩油門到底........阿!!啥極速才90公里喔!!!舒馬克夠爛.........還號稱是車神.......
給台法拉利讓我開........看我神氣坐上駕駛座發動引擎......大腳一踩油門到底........阿!!啥極速才60公里喔!!!法拉利夠爛.........還號稱是超級跑車.......
編輯記錄
jcjroc 重新編輯於 2011-07-26 23:59:44, 註解 無‧
jcjroc 重新編輯於 2011-07-27 00:06:58, 註解 無‧
macchen
初階會員


發表:66
回覆:102
積分:33
註冊:2006-07-07

發送簡訊給我
#31 引用回覆 回覆 發表時間:2011-07-27 14:01:42 IP:219.87.xxx.xxx 訂閱
好吧,感謝你的回覆,我沒有慧根,還是不了解,但畢竟我是發問問題的人,本來就該虛心指教,並且不是每個人都願意教導別人的,謝謝大家。
===================引 用 jcjroc 文 章===================
舒馬克當然是車神...........極速90是因為給他的車是台20幾年前的裕隆速利1200
法拉利當然是超級跑車...........問題是我不知道要換檔......................

以上的共通點是......裕隆速利是我給舒馬克的................法拉利是我開的..........
結論是不管法拉利或是舒馬克都很爛............而我是最好的............

程式跑不快...........是硬體還是軟體關係?????阿災............反正這時候我是路人甲買醬油路過的.......

題外話........如果你的題目是我做的話,依需求,對我來說會趨近線性沒錯.

------
DELPHI初學者
[<<] [1] [2] [>>]
系統時間:2017-10-19 13:28:21
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!