1

ある種のタイミングの問題のように見えるバグを調査しているので、Delphi 7 でイベントがどのように機能するかについて少し興味があります。何が起こるかというと、COM インターフェイスを介してアプリケーションにデータが送信され、それが処理されます。 COM スレッドから発生するイベント。かなりの量のコードが含まれているイベントは、実行に時間がかかり、しばらくするとアプリケーション全体がクラッシュするようです。時間に影響を与える可能性のあるイベント内の大きな配列へのグラフィックスとスタッフィングへの呼び出しがあります。メモリ使用量の大幅な増加を見つけることができず、プロファイラーを実行してリークをチェックする機会がまだありませんでした。また、テストする明白なことは、より長い期間実行できるかどうかを確認するためだけに、その中のすべてのコードのイベントを削除することです.

Delphi では、イベントはシリアルですか、それともパラレルですか。つまり、イベントの実行中に新しいイベントを取得するとどうなりますか? ある種の自動スレッドで並行して実行されますか、無視されますか、それともキューに入れられますか?

キューに入れられた場合、アプリケーションがクラッシュする前にキューに何個入れることができますか?

大きな配列へのインデックス付けは、深くなるほど時間がかかりますか? 固定サイズでも?そうすべきではないと思うので、時間がかかるリークと割り当てを探しています。イベントを通じてオブジェクトが送信された場合、イベント内または「呼び出し」コード内で破棄する必要がありますか?

通常、Delphi でうまくスケーリングできないものは何ですか? 実行時間が長くなるものを探すにはどうすればよいですか?

最後に、これは COM に関連しているため、COM の一般的な落とし穴へのポインターは高く評価されますが、これは注意が必要です。ただし、共同初期化を把握しています。

4

3 に答える 3

2

Delphi は、ほとんどの場合、イベントを逐次的に処理します。残念ながら、すでに何らかのイベントを実行しているときに、Delphi に他のイベントを処理するように指示することは可能です。その結果、現在のイベントが新しいイベントの終了を待っている間に、新しいイベントが実行されます。最悪の場合、実際にはイベント内のイベント内にイベントをスタックしているにもかかわらず、アプリケーションが正常に動作しているように見えることがあります。ルール 1: 本当に必要でない限り、Application.ProcessMessages の使用は避けてください。

COM オブジェクトを使用する場合、COM オブジェクトには独自のイベントがあり、独自のスレッドを開始し、制御できない他のすべての種類のことを実行する可能性があるため、事態は少し複雑になります。COM は Delphi で簡単に使用できるように見えますが、経験の浅い開発者にとっては多くの落とし穴があります。(いくつかの傷を生き延びた後、私はまだ傷跡を持っています!)

一般に、COM オブジェクトを操作するときは、COM 呼び出しを独自のスレッドに分離して、COM オブジェクトを独自のスレッド内に保持する特別なコンポーネントを作成し、多くの同期コードを追加して、GUI の応答性を維持できるようにします。いくつかの長い COM タスクが何らかの処理を行っている間。ただし、これを行うには、COM とマルチスレッドに関する多くの経験が必要です。ただし、基本的には、COM クラスが必要とするリソースを保護するためだけに、COM コンポーネントの周りにカスタム ラッパー コンポーネントを設計することをお勧めします。

Delphi の最大の弱点は、文字列の処理と巨大な配列の処理です。(特にオブジェクトを含む配列。代わりにレコードを使用してください。)Delphi では文字列自体は高速ですが、Delphi の文字列関数はあまり最適化されていません。たとえば、ある XML データを含む文字列があったとします。「True」と「False」のように綴られた多くのブールフィールドがあり、それらを「true」と「false」に変換する必要がありました。単純な文字列置換では、これらすべての値を置換するのに約 15 秒かかりました。MSXML を使用して XML を DOM ドキュメントにロードし、XPath を使用してすべてのブール ノードを選択し、それらのノードをループしてすべての値を適切なテキストに置き換え、XML を 1 つの文字列に戻すことで書き直しました。突然、2 秒以内に同じことができるようになりました。遅いように見えたもののパフォーマンスが大幅に向上しました。理由?Delphi が文字列を処理する場合、処理中に文字列を数回コピーする傾向があります。または、文字列のサイズを大きくするには、より多くのメモリを割り当てる必要があります。これには時間がかかりますが、C++ などの他の言語では無駄になりません。

于 2009-06-08T15:18:48.817 に答える
0

COM にとって重要なことは、アプリケーションがサポートしている「アパートメント モデル」です。Delphi で最も一般的に使用されるのは、COM 呼び出しがアプリケーションのメイン メッセージ キューと同期される「アパートメント スレッド」とも呼ばれるシングル スレッド アパートメント モデルです。このモデルでは、一度に 1 つの COM 呼び出ししか処理できず、COM オブジェクトは他のスレッドからの呼び出しをサポートしていません。

ただし、COM アパートメント モデルをマルチスレッドに初期化することはできます。その際、共有リソースへのアクセスが適切に同期されていることを確認する必要があります。開始する各スレッドは、呼び出してマルチスレッド アパートメントに参加する必要があります。CoInitializeEx(nil, COINIT_MULTITHREADED);

RPC サブシステムには要求を処理するためのスレッド プールがあり、マルチスレッド アパートメント内のすべての COM オブジェクトに直接アクセスできるため、DCOM インターフェイスを公開すると、非常に興味深いことが起こります。これにより、高性能サーバーが可能になります。アパートメント スレッドを使用している場合は、メッセージ キューのボトルネックを通過する必要があり、シングル スレッドは一度に 1 つの COM 呼び出ししかディスパッチできません。

Chris Bensenは、いくつかのコード サンプルとともに、これについても素晴らしいブログ投稿を書きました。

于 2009-06-09T22:13:41.067 に答える
0

特に私の最初の質問に対して、いくつかの調査を行い、いくつかの指針を得ました。

Delphi では、イベントはシリアルですか、それともパラレルですか。つまり、イベントの実行中に新しいイベントを取得するとどうなりますか? ある種の自動スレッドで並行して実行されますか、無視されますか、それともキューに入れられますか? キューに入れられた場合、アプリケーションがクラッシュする前にキューに何個入れることができますか?

明らかに、イベントは他のすべてのものと同じように同期的です。つまり、シリアルと言うべきでしょう。そのイベントは本質的に関数呼び出しであるため、1 つを処理するときにそれ以上のイベントを取得することはできません。

イベント ハンドラーでは、いくつかのグラフィック コンポーネントが処理されます。イベントは別のスレッドで発生するため、これは悪いことです。グラフィックスを作成したスレッド上にあるグラフィックスの更新メカニズムを作成するか、イベントでスレッドを切り替える必要があります。

また、テストによると、実際にはグラフィックスの更新にますます時間がかかっていることが示されているため、グラフィックス処理のリファクタリングは、最初に試すのに適した方法のように思えます。

于 2008-12-18T07:39:44.923 に答える