線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:4198
推到 Plurk!
推到 Facebook!

關於Synchronize的疑問

答題得分者是:carstyc
windheartalan
一般會員


發表:21
回覆:23
積分:8
註冊:2005-03-24

發送簡訊給我
#1 引用回覆 回覆 發表時間:2009-06-22 14:25:58 IP:60.248.xxx.xxx 訂閱
各位大大好,有關於Synchronize的問題想請教,

我有寫一支程式,除了主執行緒之外,為了不影響畫面的展現(不要有hang住狀況),
所以有另起thread來處理socket資料的收送,以及邏輯處理,展現等等,
由於裡面不可避免的有用到一些vcl元件,因此在thread的exe中,於處理的procedure就加上了Synchronize,
就之前認知是,於thread中使用不是thread safe的元件,就必須加上這個關鍵字,

問題來了,經過實際的執行,感覺畫面仍然是會有短時間頓住的情形,
後來去爬了以往網友的文章,知道Synchronize其實是把裡面的東西搬回給主執行緒來做,
那這樣的話,感覺另起thread就沒有意義了,

想請問這樣的case,有什麼解決方法嗎? 就是在thread中,會需要用到一些vcl元件的情況下,
要如何才能不使畫面會有短時間的hang住情形?

我是不知道Synchronize除了放在thread.Execute這個procedure之外,
可否放在別的procedure裡,又或者Synchronize是否可以放可傳回值的function?

現在程式是類似這樣:
procedure TParseData.Execute;
begin
while not Terminated do begin
try
Synchronize(SendData);
except
Suspend;
end;
end;
end;

可以改成這樣嗎? 會有用嗎?
procedure TParseData.Execute;
begin
while not Terminated do begin
try
ParseData
except
Suspend;
end;
end;
end;

procedure TParseData.ParseData;
begin

XXXX
Synchronize(ProcessData);
XXXX

end;

請各位大大指教,感謝.








aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#2 引用回覆 回覆 發表時間:2009-06-22 18:29:39 IP:210.64.xxx.xxx 訂閱
可以。

搬回主thread沒錯,但理論上速度不會影響很大。因為會回主thread處理的都是一些可視元件,比如說labe,edit 等…

除非你大量的更新memo之類裡的資料。

thread裡主要還是要處理大量的運算或是io,ui才用synchronize暫調回主thread
------


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

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
RootKit
資深會員


發表:16
回覆:358
積分:419
註冊:2008-01-02

發送簡訊給我
#3 引用回覆 回覆 發表時間:2009-06-22 20:42:47 IP:122.126.xxx.xxx 訂閱
補充:

應該在 SendData 中有包含 Socket 運作當花費了 一些時間。
盡量使用透過變數暫存的方式,畫面顯示是很快的(不容易察覺),除非常常刷新畫面。

運算與執行(Thread)->寫入暫存(Thread)->通知畫面刷新 ->更新畫面(主程式)
carstyc
資深會員


發表:16
回覆:254
積分:329
註冊:2003-07-18

發送簡訊給我
#4 引用回覆 回覆 發表時間:2009-06-23 01:00:14 IP:219.84.xxx.xxx 訂閱
不知道你在SendData 裡面做了啥事?

一般人只要碰到有沾到 non thread safe 的 元件,就全部把它包起來,然後用 Synchronize 去跑,就以為萬無一失了。


可是....如果全部都包起來,再用Synchronize 去跑,整個Thread裡面就只跑一個程序,並且用Synchronize執行,那跟直接寫在Main Thread 裡面有啥差別? (應該也是有一點差別啦,但只是概略詞句,請各位大大勿見怪)

你可以試著把你要處理的邏輯,與要呈現 vcl 結果的部份分離處理,複雜的邏輯部份放在Thread 裡面去跑,然後再把跑出來的結果,要呈現在VCL的部份,再包到 Synchronzie 的程序裡面去。這樣也許能解決你的問題。

但如何分離,就要靠你的功力了。

但如果你的主要loading 就是在 vcl 呈現的變化處理話,無論你放在那裡執行,它該會慢就是會慢,也許不是Thread的問題,是你的 VCL refresh 速度跟不上你的處理速度。




===================引 用 windheartalan 文 章===================
各位大大好,有關於Synchronize的問題想請教,

我有寫一支程式,除了主執行緒之外,為了不影響畫面的展現(不要有hang住狀況),
所以有另起thread來處理socket資料的收送,以及邏輯處理,展現等等,
由於裡面不可避免的有用到一些vcl元件,因此在thread的exe中,於處理的procedure就加上了Synchronize,
就之前認知是,於thread中使用不是thread safe的元件,就必須加上這個關鍵字,

問題來了,經過實際的執行,感覺畫面仍然是會有短時間頓住的情形,
後來去爬了以往網友的文章,知道Synchronize其實是把裡面的東西搬回給主執行緒來做,
那這樣的話,感覺另起thread就沒有意義了,

想請問這樣的case,有什麼解決方法嗎? 就是在thread中,會需要用到一些vcl元件的情況下,
要如何才能不使畫面會有短時間的hang住情形?

我是不知道Synchronize除了放在thread.Execute這個procedure之外,
可否放在別的procedure裡,又或者Synchronize是否可以放可傳回值的function?

現在程式是類似這樣:
procedure TParseData.Execute;
begin
while not Terminated do begin
try
Synchronize(SendData);
except
Suspend;
end;
end;
end;

可以改成這樣嗎? 會有用嗎?
procedure TParseData.Execute;
begin
while not Terminated do begin
try
ParseData
except
Suspend;
end;
end;
end;

procedure TParseData.ParseData;
begin

XXXX
Synchronize(ProcessData);
XXXX

end;

請各位大大指教,感謝.








windheartalan
一般會員


發表:21
回覆:23
積分:8
註冊:2005-03-24

發送簡訊給我
#5 引用回覆 回覆 發表時間:2009-06-23 14:53:53 IP:219.84.xxx.xxx 訂閱

Socket運作部分已經在另一個地方處理完了,
這個thread是把Socket收到的內容放在List中,
然後一個個內容取出來處理,

Synchronize內有用到vcl的部份,大概就是將這些內容處理後展現在grid上,
如大大所說,由於socket資料量多且頻繁,所以grid的畫面刷新也是很頻繁的,

想克服的問題就在這個部份,就算我邏輯切開了,
在刷新頻率如此頻繁的情況下,畫面的展現就不會頓一下了嗎?

若有大大有一些不同的思考方向,請給予指教,謝謝.


===================引 用 RootKit 文 章===================
補充:

應該在 SendData 中有包含 Socket 運作當花費了 一些時間。
盡量使用透過變數暫存的方式,畫面顯示是很快的(不容易察覺),除非常常刷新畫面。

運算與執行(Thread)->寫入暫存(Thread)->通知畫面刷新 ->更新畫面(主程式)
windheartalan
一般會員


發表:21
回覆:23
積分:8
註冊:2005-03-24

發送簡訊給我
#6 引用回覆 回覆 發表時間:2009-06-23 15:00:51 IP:211.75.xxx.xxx 訂閱

看到大大以下的說明想請教一件事,讓我能釐清觀念,
synchronize中的code,是只有vcl的元件會交給主thread處理,
還是說只要用synchronize包起來的部份,全部都是在主thread處理,

以上述的範例來討論,
execute裡面就一個senddata讓synchronize包住,
以後者的解釋來說,等於沒有使用thread?

以前者解釋,就是只有用到grid,edit等vcl時,如資料的存取或畫面的刷新時才會交給主thread處理,
其他的邏輯運算還是在另一個thread處理,這樣這個thread還有一點意義,

請問是何者呢? 感謝各位先進的指教.


===================引 用 aftcast 文 章===================
可以。

搬回主thread沒錯,但理論上速度不會影響很大。因為會回主thread處理的都是一些可視元件,比如說labe,edit 等…

除非你大量的更新memo之類裡的資料。

thread裡主要還是要處理大量的運算或是io,ui才用synchronize暫調回主thread
carstyc
資深會員


發表:16
回覆:254
積分:329
註冊:2003-07-18

發送簡訊給我
#7 引用回覆 回覆 發表時間:2009-06-23 16:21:47 IP:203.79.xxx.xxx 訂閱
如此看起來,你的問題應該是 Grid refresh 的頻率過高,導致畫面遲頓的。

但是以一個Grid 可視範圍不過是幾十個 row ,就算大量的refresh ,也應該不至於有遲頓的現象才對。

是不是你的Grid 裡面有幾仟幾萬行的 row,然後你只更新其中幾個 row 的資料,然後就將整個Grid 重新 refresh 一次。

如果是這樣的話,你可以考慮把 Grid 的 Row Count 限制在一定範圍內,比如30行或50行,然後就只針對這幾十行的資料做Refresh,效能上應該就ok了。

因為Grid 的可視範圍就這幾十行,你把幾仟行幾萬行的row data 全部refresh 是沒啥意義的,把看不見的資料先移開Grid,應該能使它的效能更好一點。

以上僅是猜測,因為不確定你的程序內容為何?


===================引 用 windheartalan 文 章===================

Socket運作部分已經在另一個地方處理完了,
這個thread是把Socket收到的內容放在List中,
然後一個個內容取出來處理,

Synchronize內有用到vcl的部份,大概就是將這些內容處理後展現在grid上,
如大大所說,由於socket資料量多且頻繁,所以grid的畫面刷新也是很頻繁的,

想克服的問題就在這個部份,就算我邏輯切開了,
在刷新頻率如此頻繁的情況下,畫面的展現就不會頓一下了嗎?

若有大大有一些不同的思考方向,請給予指教,謝謝.


===================引 用 RootKit 文 章===================
補充:

應該在 SendData 中有包含 Socket 運作當花費了 一些時間。
盡量使用透過變數暫存的方式,畫面顯示是很快的(不容易察覺),除非常常刷新畫面。

運算與執行(Thread)->寫入暫存(Thread)->通知畫面刷新 ->更新畫面(主程式)
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#8 引用回覆 回覆 發表時間:2009-06-23 16:25:07 IP:210.64.xxx.xxx 訂閱
應該要很謝謝樓上的前輩來補充。我才想說我只寫標題大綱,就有rootkit兄來簡答,然後最後又被深論… ^_^

Synchronized(a)時,表示a方法裡的所有程式碼都會被移至main thread上執行。所以,通常a裡面的實作將是非常簡單的,比如說
Form1->Label = as;
就這麼一句話。
但重點在於as這個變數可能是經過無數的計算得到的結果,而這些計算就不應該放在a這個method中。
這樣才可以確保運算是在子 thread裡,但更新時暫回mainthread。
以下使用虛擬碼說明一下:
static AnsiString as; // 全域
Thread1::Execute
{
.........
foo = "xxxx";
bar = foo "xdsf";
for (i=0;i<1000;i )
as = as IntToStr(i)
as = as bar;
Synchronize(a);
.....
...
}

Thread1::a(void)
{
Form1->Label = as;
}

結束虛擬碼說明

此外,以你這個情形來看,我個人猜測…
最主要的原因有你的socket是使用message drive的方式,簡單講就是如TClientSocket這類的元件。
它是在收到訊息時會以message的方式通知你的mainform,然後你處理on receive的事件這種。
所以,很可能你的mainform(主thread)本身就被這些message塞到不行,若你的子thread這時候插隊要暫時跑更新ui… 那…肯定會頓的。
此外,另一個很大的重點是: 你的 on receive的處理函式很有可能處理很多的運算,這時候main thread就超忙的,沒時間去處理別的事件。

結論: 可以把on receive裡的工作全部移到另一個thread上跑。或是整合在上述的一個thread裡。比如說
mainform socket_thread (這個thread處理 on receive事件的事,並試著去更新mainform上的ui)

mainform socket_thread(只處理on receive的資料) update_thread(進一步處理收到的內容 更新ui)

一般來說,應該第一種模式就夠用!

不知你是怎麼設計你的socket的… 所以也沒辦法正確的指出問題和改善方式。除非你把架構與部份程式碼都貼出來…
但,以上的訊息加上樓上二位高手的提示,應該足以解決了吧! ^_^
------


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

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
carstyc
資深會員


發表:16
回覆:254
積分:329
註冊:2003-07-18

發送簡訊給我
#9 引用回覆 回覆 發表時間:2009-06-23 16:32:04 IP:203.79.xxx.xxx 訂閱
據我知道的...

Synchronize 主要是怕 Non Thread Safe 的 元件同時有多個Thread 執行到,會有不可預期的現象發生。

所以 Synchronize 能確保該永遠只有一個Thread在執行該程序。

所以它是將整個程序交給Main Thread 來執行。而不是會聰明到自己判斷程序中那些給Main Thread做,那些留在自己的Thread做。



===================引 用 windheartalan 文 章===================

看到大大以下的說明想請教一件事,讓我能釐清觀念,
synchronize中的code,是只有vcl的元件會交給主thread處理,
還是說只要用synchronize包起來的部份,全部都是在主thread處理,

以上述的範例來討論,
execute裡面就一個senddata讓synchronize包住,
以後者的解釋來說,等於沒有使用thread?

以前者解釋,就是只有用到grid,edit等vcl時,如資料的存取或畫面的刷新時才會交給主thread處理,
其他的邏輯運算還是在另一個thread處理,這樣這個thread還有一點意義,

請問是何者呢? 感謝各位先進的指教.


===================引 用 aftcast 文 章===================
可以。

搬回主thread沒錯,但理論上速度不會影響很大。因為會回主thread處理的都是一些可視元件,比如說labe,edit 等…

除非你大量的更新memo之類裡的資料。

thread裡主要還是要處理大量的運算或是io,ui才用synchronize暫調回主thread
windheartalan
一般會員


發表:21
回覆:23
積分:8
註冊:2005-03-24

發送簡訊給我
#10 引用回覆 回覆 發表時間:2009-06-23 17:19:46 IP:211.75.xxx.xxx 訂閱
謝謝大大的建議,其實可視資料範圍也不大,
不過由於有時候要清掉某些row,會需要掃一次迴圈,也許是這裡有影響吧.
像這個部份,也很難去拆出邏輯跟可視元件的部份,因為是要根據可視元件裡的資料來做一些判斷,
如果另外new一個structure來處理,直觀上來說等於多用一些記憶體來放,
但如此也許可以減輕存取可視元件的次數,不知這樣會不會比較快就是了,

我說頓頓的,其實也不算是長時間的hang住,但仍會感覺出來,資料量大時會有1~2秒的遲鈍現象,
所以才在想說,有沒有辦法改善,

大大所說的方向我能夠理解,就得好好想想要怎麼拆囉,謝謝.

===================引 用 carstyc 文 章===================
如此看起來,你的問題應該是 Grid refresh 的頻率過高,導致畫面遲頓的。

但是以一個Grid 可視範圍不過是幾十個 row ,就算大量的refresh ,也應該不至於有遲頓的現象才對。

是不是你的Grid 裡面有幾仟幾萬行的 row,然後你只更新其中幾個 row 的資料,然後就將整個Grid 重新 refresh 一次。

如果是這樣的話,你可以考慮把 Grid 的 Row Count 限制在一定範圍內,比如30行或50行,然後就只針對這幾十行的資料做Refresh,效能上應該就ok了。

因為Grid 的可視範圍就這幾十行,你把幾仟行幾萬行的row data 全部refresh 是沒啥意義的,把看不見的資料先移開Grid,應該能使它的效能更好一點。

以上僅是猜測,因為不確定你的程序內容為何?


===================引 用 windheartalan 文 章===================

Socket運作部分已經在另一個地方處理完了,
這個thread是把Socket收到的內容放在List中,
然後一個個內容取出來處理,

Synchronize內有用到vcl的部份,大概就是將這些內容處理後展現在grid上,
如大大所說,由於socket資料量多且頻繁,所以grid的畫面刷新也是很頻繁的,

想克服的問題就在這個部份,就算我邏輯切開了,
在刷新頻率如此頻繁的情況下,畫面的展現就不會頓一下了嗎?

若有大大有一些不同的思考方向,請給予指教,謝謝.


===================引 用 RootKit 文 章===================
補充:

應該在 SendData 中有包含 Socket 運作當花費了 一些時間。
盡量使用透過變數暫存的方式,畫面顯示是很快的(不容易察覺),除非常常刷新畫面。

運算與執行(Thread)->寫入暫存(Thread)->通知畫面刷新 ->更新畫面(主程式)
windheartalan
一般會員


發表:21
回覆:23
積分:8
註冊:2005-03-24

發送簡訊給我
#11 引用回覆 回覆 發表時間:2009-06-23 17:42:04 IP:211.75.xxx.xxx 訂閱
{
它是在收到訊息時會以message的方式通知你的mainform,然後你處理on receive的事件這種。
所以,很可能你的mainform(主thread)本身就被這些message塞到不行,若你的子thread這時候插隊要暫時跑更新ui… 那…肯定會頓的。
此外,另一個很大的重點是: 你的 on receive的處理函式很有可能處理很多的運算,這時候main thread就超忙的,沒時間去處理別的事件。
}

我應該是大大所敘述的這種情形,處理程序部分,我目前應該已是大大所描述的方法二,
mainform socket_thread(只處理on receive的資料) update_thread(進一步處理收到的內容 更新ui)

只是我的update_thread,看起來用到vcl的地方很多,當時求快,沒有切的很清楚,現在要分就麻煩了... ^^"

然後今天還有一個發現,因為我的socket是有收也有送的情況,
我發覺光是大量的收(含update 視覺化元件),狀況是還好,最多覺得有些遲鈍,但沒有整個頓住,

不過若我同時也發出socket send,在同時收送加上update vcl的情形下,就會有我說的頓一兩秒的情況了,
這樣看來,光是修改收的部份邏輯,可能也沒有太大幫助,

不知道問題是不是反而是出在大大所說的,使用message drive的方式,同時收送造成系統太忙碌所致,(收送都有另起thread處理),
如果是這樣就比較麻煩,是不是代表用TClientSocket就無可避免會碰上這種狀況呢?
那用indy socket元件的話,他算是message drive元件嗎? 因為它還是有部份是event觸發,但收送不是,
觀念不是很清楚,所以不了解,請大大釋疑. ^^"

各位回文的大大都讓我學習不少,也釐清了一些觀念,謝謝~


===================引 用 aftcast 文 章===================
應該要很謝謝樓上的前輩來補充。我才想說我只寫標題大綱,就有rootkit兄來簡答,然後最後又被深論… ^_^

Synchronized(a)時,表示a方法裡的所有程式碼都會被移至main thread上執行。所以,通常a裡面的實作將是非常簡單的,比如說
Form1->Label = as;
就這麼一句話。
但重點在於as這個變數可能是經過無數的計算得到的結果,而這些計算就不應該放在a這個method中。
這樣才可以確保運算是在子 thread裡,但更新時暫回mainthread。
以下使用虛擬碼說明一下:
static AnsiString as; // 全域
Thread1::Execute
{
.........
foo = "xxxx";
bar = foo "xdsf";
for (i=0;i<1000;i )
as = as IntToStr(i)
as = as bar;
Synchronize(a);
.....
...
}

Thread1::a(void)
{
Form1->Label = as;
}

結束虛擬碼說明

此外,以你這個情形來看,我個人猜測…
最主要的原因有你的socket是使用message drive的方式,簡單講就是如TClientSocket這類的元件。
它是在收到訊息時會以message的方式通知你的mainform,然後你處理on receive的事件這種。
所以,很可能你的mainform(主thread)本身就被這些message塞到不行,若你的子thread這時候插隊要暫時跑更新ui… 那…肯定會頓的。
此外,另一個很大的重點是: 你的 on receive的處理函式很有可能處理很多的運算,這時候main thread就超忙的,沒時間去處理別的事件。

結論: 可以把on receive裡的工作全部移到另一個thread上跑。或是整合在上述的一個thread裡。比如說
mainform socket_thread (這個thread處理 on receive事件的事,並試著去更新mainform上的ui)

mainform socket_thread(只處理on receive的資料) update_thread(進一步處理收到的內容 更新ui)

一般來說,應該第一種模式就夠用!

不知你是怎麼設計你的socket的… 所以也沒辦法正確的指出問題和改善方式。除非你把架構與部份程式碼都貼出來…
但,以上的訊息加上樓上二位高手的提示,應該足以解決了吧! ^_^
系統時間:2024-11-22 16:09:20
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!