關於Synchronize的疑問 |
答題得分者是:carstyc
|
windheartalan
一般會員 發表:21 回覆:23 積分:8 註冊:2005-03-24 發送簡訊給我 |
各位大大好,有關於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 發送簡訊給我 |
可以。
搬回主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 發送簡訊給我 |
|
carstyc
資深會員 發表:16 回覆:254 積分:329 註冊:2003-07-18 發送簡訊給我 |
不知道你在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 發送簡訊給我 |
Socket運作部分已經在另一個地方處理完了, 這個thread是把Socket收到的內容放在List中, 然後一個個內容取出來處理, Synchronize內有用到vcl的部份,大概就是將這些內容處理後展現在grid上, 如大大所說,由於socket資料量多且頻繁,所以grid的畫面刷新也是很頻繁的, 想克服的問題就在這個部份,就算我邏輯切開了, 在刷新頻率如此頻繁的情況下,畫面的展現就不會頓一下了嗎? 若有大大有一些不同的思考方向,請給予指教,謝謝. ===================引 用 RootKit 文 章=================== 補充: 應該在 SendData 中有包含 Socket 運作當花費了 一些時間。 盡量使用透過變數暫存的方式,畫面顯示是很快的(不容易察覺),除非常常刷新畫面。 運算與執行(Thread)->寫入暫存(Thread)->通知畫面刷新 ->更新畫面(主程式) |
windheartalan
一般會員 發表:21 回覆:23 積分:8 註冊:2005-03-24 發送簡訊給我 |
看到大大以下的說明想請教一件事,讓我能釐清觀念, 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 發送簡訊給我 |
如此看起來,你的問題應該是 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 發送簡訊給我 |
應該要很謝謝樓上的前輩來補充。我才想說我只寫標題大綱,就有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 發送簡訊給我 |
據我知道的...
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 發送簡訊給我 |
謝謝大大的建議,其實可視資料範圍也不大,
不過由於有時候要清掉某些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 發送簡訊給我 |
{
它是在收到訊息時會以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的… 所以也沒辦法正確的指出問題和改善方式。除非你把架構與部份程式碼都貼出來… 但,以上的訊息加上樓上二位高手的提示,應該足以解決了吧! ^_^ |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |