2008-12-16 190 views
1

我正在研究一個看起來像某種時間問題的錯誤,所以我對Delphi 7中事件的工作方式有點好奇。然後我們通過一個函數發送一些數據給我們的應用程序COM接口,並在COM線程引發的事件中處理它。看起來事件中有很多代碼,執行需要的時間越來越長,過了一段時間後整個應用程序崩潰了。在圖形和事件內部的大數組中存在可能影響時間的調用。我一直無法發現任何顯着的內存使用量增加,並沒有機會運行任何分析器來檢查泄漏。另外,要測試的顯而易見的事情是將其中所有代碼的事件剝離,以查看我們是否可以運行更長的時間。德爾福7和事件

Delphi中的事件是串行或並行的,也就是說,如果我在執行一個新事件時發生了什麼 - 發生了什麼?它是否在某種自動線程中並行運行,是忽略還是排隊?

如果排隊等候,應用程序崩潰之前我可以在隊列中擁有多少個隊列?

索引到一個大陣列需要更長的時間進一步進入它你是?即使它的大小是固定的?我認爲這不應該讓我尋找需要時間的泄漏和分配。如果我通過事件發送了一個對象,我應該在事件內還是在「調用」代碼中處理它?

什麼東西通常在Delphi中不能很好地擴展?我能找到什麼會增加執行時間?

最後,由於這是COM相關的,任何指向COM常見陷阱的指針都會被讚賞,儘管我意識到這很棘手。儘管如此,我確實掌握了共同初始化。

回答

0

做了一些研究,並得到了幾個三分球,特別是我的第一個問題:

事件是在Delphi串行或parallell,也就是說,如果我當一個新的事件正在執行 - 什麼情況?它是否在某種自動線程中並行運行,是忽略還是排隊? 如果排隊,在應用程序崩潰之前,我可以在隊列中擁有多少個隊列?

好吧,顯然事件與其他事物一樣是同步的,或者我應該說是連續的。由於該事件本質上是一個函數調用,因此在處理一個事件時無法獲得更多事件。

在事件處理程序中,會處理一些圖形組件。由於該事件在另一個線程中引發,因此這是不好的。我需要對創建圖形的線程上的圖形或者在事件中進行線程切換的圖形進行更新。

另外,測試表明它實際上是圖形的更新花費的時間越來越長,因此重構圖形處理聽起來像是一個很好的嘗試的路徑。

2

德爾福主要是處理事件的串行。不幸的是,有可能告訴德爾福在處理某些事件時處理其他事件。因此,當您的當前事件正在等待新事件完成時,新事件將運行。在最糟糕的情況下,您的應用程序可能看起來行爲正常,而事件內事件內的事件實際上是在堆疊事件。規則一:避免使用Application.ProcessMessages,除非你真的需要這個。

當使用COM對象,事情變得更加複雜一點,因爲COM對象可能有它自己的事件,開始它自己的主題,做所有其他類型的東西,你沒有任何控制權。 COM似乎很容易在Delphi中使用,但對於缺乏經驗的開發人員來說,它確實存在許多隱藏的缺陷。 (我在倖存其中一些人後仍然留下疤痕!)

一般來說,當使用COM對象時,我嘗試在自己的線程中分離COM調用,創建特殊組件,將COM對象保留在其中自己的線程並添加大量的同步代碼,這樣我可以保持圖形用戶界面的響應,而一些長的COM任務正在做一些處理。但是這樣做需要很多COM和多線程的經驗。但基本上,圍繞任何COM組件設計自定義包裝器組件是一種很好的做法,只是爲了保護COM類所需的資源。

德爾福最強大的弱點往往是字符串處理和巨大數組的處理。 (尤其是包含對象的數組;使用記錄代替。)Delphi中的字符串本身很快,但Delphi中的字符串函數並不是非常優化的。例如,我曾經有一個包含一些XML數據的字符串。它有許多布爾字段拼寫爲「True」和「False」,需要將它們轉換爲「true」和「false」。一個簡單的字符串替換大約需要15秒來替換所有這些值。我通過使用MSXML將XML加載到DOM文檔中,使用XPath選擇所有布爾節點,通過這些節點循環來將所有值替換爲正確的文本,然後將XML放回到單個字符串中,從而重寫了它。突然之間,它能夠在兩秒鐘內做到這一點!對於那些看起來比較慢的東西來說,這是一個巨大的表現。 原因?當Delphi處理字符串時,往往會在處理過程中複製字符串幾次。或者它需要分配越來越多的內存來增加字符串的大小。這需要時間,這不會浪費在像C++這樣的其他語言中。

+0

我完全不同意你的最後一段。天真==慢字符串處理可以在每種語言中實現,當然也可以在C++中實現。用一個適當的算法在字符串中將True和False置爲小寫,應該可以處理每秒幾兆字節。如果(取決於字符串長度)10秒或100毫秒是可能的,從15秒到2秒?我不知道... – mghie 2009-06-08 19:06:49

0

COM的重要之處在於你的應用程序支持的「公寓模型」。在Delphi中最常用的是Single Threaded Apartment model也被稱爲「公寓線程」,其中COM調用與您的應用程序主消息隊列同步。使用這個模型,你一次只能處理一個COM調用,COM對象不支持來自其他線程的調用。通過調用CoInitializeEx(nil, COINIT_MULTITHREADED);

每次啓動線程將不得不加入多線程公寓 -

但是,您可以初始化COM單元模型是multithreaded並在這樣做,你將不得不作出對共享資源確保獲得正確同步

當您公開DCOM接口時,事情會變得非常有趣,因爲RPC子系統有一個線程池用於處理請求,這些請求可以直接訪問多線程單元中的所有COM對象,從而實現高性能服務器。如果您正在使用單元線程,則必須經歷消息隊列的瓶頸,並且單線程一次只能分派一個COM調用。

克里斯·本森寫了nice blogpost這個也有一些代碼示例。