web-dev-qa-db-ja.com

Delphiでスレッド化を行うためのさまざまな方法から選択するにはどうすればよいですか?

Delphi2009プログラムになんらかのスレッドを実装する必要があるようです。それを行う方法が1つしかない場合、私は立ち去って走っています。しかし、いくつかの可能性があります。

誰かがこれらの違いは何ですか、そしてなぜ私がどちらかを選ぶのか説明できますか?.

  1. DelphiのTThreadクラス

  2. AsyncCalls by Andreas Hausladen

  3. OmniThreadLibrary by Primoz Gabrijelcic(gabr)

  4. ... 他のもの?


編集:

2010年3月号(No 10)のGabrによる Blaise Pascal Magazine 「スレッドを作成する4つの方法」というタイトルの優れた記事を読みました。雑誌のコンテンツを入手するには購読する必要があるため、著作権により、ここでは実質的な内容を複製することはできません。

要約すると、Gabrは、TThreads、直接Windows API呼び出し、AndyのAsyncCalls、および彼自身のOmniThreadLibraryの使用の違いについて説明しています。彼は最後に次のように結論付けています。

「古典的なDelphiの方法(TThread)以外のものを選択する必要があると言っているわけではありませんが、それでも、使用できるオプションについて通知を受けるのは良いことです。」

Mghieの答えは非常に徹底的であり、OmniThreadLibraryが望ましいかもしれないことを示唆しています。しかし、私(または誰か)がアプリケーションのスレッド化方法をどのように選択すべきかについてのみんなの意見にはまだ興味があります。

そして、あなたはリストに追加することができます:

。 4. WindowsAPIへの直接呼び出し

。 5. Misha Charrett'sCSI Distributed Application Framework LachlanGの回答で示唆されているとおり。


結論:

私はおそらくOmniThreadLibraryを使うつもりです。 Gabrの作品が好きです。私は何年も前に彼のプロファイラーGPProfileを使用していましたが、現在は実際にはOTLの一部である彼のGPStringHashを使用しています。

私の唯一の懸念は、Embarcaderoがその機能をDelphiに追加した後、64ビットまたはUnix/Mac処理で動作するようにアップグレードすることかもしれません。

63
lkessler

マルチスレッドの経験がない場合は、おそらくTThreadから始めるべきではありません。それは、ネイティブスレッドの上の薄い層です。また、端が少し荒いこともあると思います。 Delphi 2の導入以来、あまり進化していません。ほとんどの場合、Kylixの時間枠でLinuxとの互換性を確保し、より明白な欠陥を修正するために変更されています(壊れたMREWクラスの修正、最終的にSuspend()の非推奨など)。およびResume()(最新のDelphiバージョン)。

単純なスレッドラッパークラスを使用すると、基本的に開発者は低すぎるレベルに集中することになります。複数のCPUコアを適切に使用するには、スレッドではなくタスクに焦点を当てた方がよいでしょう。スレッドを使用した作業の分割は、ハードウェアと並行して実行されている他のソフトウェアによっては、変化する要件や環境にうまく適応しないためです。同じシステムの異なる時間であっても、スレッドは大きく異なる場合があります。作業のチャンクのみを渡し、利用可能なリソースを最大限に活用するためにそれらを自動的にスケジュールするライブラリは、この点で非常に役立ちます。

AsyncCallsは、アプリケーションにスレッドを導入するための良い最初のステップです。プログラム内に、互いに独立した多くの時間のかかるステップを実行する必要がある複数の領域がある場合は、それぞれをAsyncCallsに渡すことで、それらを非同期で実行できます。このような時間のかかるアクションが1つしかない場合でも、非同期で実行し、VCLスレッドで進行状況UIを表示するだけで、オプションでアクションをキャンセルできます。

AsyncCallsはIMOであり、プログラムの実行時間全体にわたって存在するバックグラウンドワーカーにはあまり適していません。また、プログラム内の一部のオブジェクトにスレッドアフィニティがある場合(データベース接続やOLE)など)は使用できない場合があります。 =すべての呼び出しが同じスレッドで発生するという要件がある可能性のあるオブジェクト)。

また、これらの非同期アクションはnot「ファイアアンドフォーゲット」の種類であることに注意する必要があります。オーバーロードされたすべてのAsyncCall()関数は、ブロッキングを回避したい場合に参照を保持する必要があるIAsyncCallインターフェースポインターを返します。参照を保持しない場合、参照カウントがゼロに達するとすぐにインターフェイスが解放されます。これにより、インターフェイスを解放するスレッドは、非同期呼び出しが完了するのを待機します。これは、デバッグ中に表示される可能性があるものです。IAsyncCallを作成したメソッドを終了すると、不思議な時間がかかる場合があります。

私の意見では、OTLは3つのオプションの中で最も用途が広く、何も考えずに使用します。 TThreadとAsyncCallsが実行できるすべてのこと、およびさらに多くのことを実行できます。それは、ユーザーの生活を楽にし、Unixyシステムへの移植を(ほとんどのインターフェースをそのままに保ちながら)簡単ではないにしても少なくとも可能に見えるようにするのに十分な高レベルのサウンドデザインを持っています。過去数か月で、並列作業用の高レベルの構成要素の取得も開始しました。これを強くお勧めします。

OTLにも数十のサンプルがあります。これは開始するために重要です。 AsyncCallsのコメントには数行しかありませんが、機能が制限されているため、理解するのは簡単です(1つのことしか実行しませんが、うまく機能します)。 TThreadのサンプルは1つだけですが、これは14年間実際には変更されておらず、ほとんどの場合、物事を行わない方法の例です。

どちらのオプションを選択しても、スレッドの基本を理解する必要がなくなるライブラリはありません。これらに関する優れた本を読んだことが、コーディングを成功させるための前提条件です。たとえば、適切なロックは、それらすべての要件です。

43
mghie

もう1つのあまり知られていないDelphiスレッドライブラリ、Misha Charrettの CSI Application Framework があります。

これは、共有メモリではなくメッセージパッシングに基づいています。同じメッセージパッシングメカニズムは、同じプロセスまたは他のプロセスで実行されているスレッド間で通信するために使用されるため、スレッドライブラリと分散プロセス間通信ライブラリの両方になります。

開始するには少し学習曲線がありますが、開始すると、デッドロックや同期などの従来のスレッドの問題をすべて心配する必要はなく、フレームワークがそのほとんどを処理します。

Mishaはこれを何年にもわたって開発しており、フレームワークとドキュメントを常に積極的に改善しています。彼は常にサポートの質問に非常に敏感です。

7
LachlanG

TThreadは、Windowsスレッドをカプセル化する単純なクラスです。このスレッドが実行する必要のあるコードを含むExecuteメソッドを使用して子孫クラスを作成し、スレッドを作成して実行するように設定すると、コードが実行されます。

AsyncCallsとOmniThreadLibraryはどちらも、スレッドの上に高レベルの概念を構築するライブラリです。それらはtasks、非同期で実行する必要がある個別の作業についてです。ライブラリを起動し、タスクプール、つまり作業が完了するまで待機する特別なスレッドのグループを設定し、コードを含む関数ポインタ(またはメソッドポインタまたは無名メソッド)をライブラリに渡します。これは実行する必要があり、タスクプールスレッドの1つで実行され、低レベルの詳細の多くを処理します。

私はどちらのライブラリもあまり使用していないので、2つのライブラリを実際に比較することはできません。それらを試してみて、彼らが何ができるか、そしてどれがあなたにとってより良いと感じるかを見てください。

6
Mason Wheeler

(申し訳ありませんが、コメントするのに十分なポイントがないので、OTLへの別の投票ではなく回答としてこれを入れています)

TThread、CSI、OmniThread(OTL)を使用しました。 2つのライブラリはどちらも自明ではない学習曲線を持っていますが、TThreadよりもはるかに優れています。私の結論は、スレッド化で重要なことをするつもりなら、とにかくライブラリ機能の半分を書くことになるので、他の誰かが書いた動作中のデバッグバージョンから始めたほうがよいということです。 MishaとGabrはどちらも私たちのほとんどよりも優れたプログラマーであるため、私たちよりも優れた仕事をしている可能性があります。

AsyncCallsを見てきましたが、私が望んでいたことを十分に実行できませんでした。それが持っているものの1つは「同期」関数(OTLにはない)です。したがって、それに依存している場合は、純粋にそのためにAynscCallsを使用することができます。メッセージパッシングを使用するIMOは、Synchronizeの厄介さを正当化するほど難しくはないので、腰を落ち着けてメッセージの使用方法を学びます。

3つのうち、私はOTLを好みます。これは、主に例のコレクションのためだけでなく、より自己完結型であるためです。すでにJCLを使用している場合や、1か所で作業している場合はそれほど問題にはなりませんが、契約作業を含めて、Mishaのシステムのインストールに関するクライアントの販売はOTLよりも難しいです。OTLが最大20ファイルであるためです。 1つのディレクトリに。それはばかげているように聞こえますが、多くの人にとって重要です。

OTLを使用すると、例とソースコードでキーワードを検索し、フォーラムで質問することを組み合わせることができます。私は従来の「CPUを集中的に使用するタスクのオフロード」スレッドジョブに精通していますが、現在、「DBを待機するスレッドブロック」がはるかに多く、「CPUが最大になっている」ことが少ないデータベース作業のヒープのバックグラウンド処理に取り組んでいます。 OTLはそのために非常にうまく機能しています。主な違いは、CPUが最大になることなく、30以上のスレッドを実行できることですが、1つを停止することは一般的に不可能です。

6
Мסž

これが最も高度な方法ではないことはわかっています:-)おそらく制限もありますが、System。BeginThreadを試してみたところ、非常に単純であることがわかりました。 -おそらく私が参照していたドキュメントの品質のために... http://www.delphibasics.co.uk/RTL.asp?Name=BeginThread (IMO NeilMoffattはMSDNに1つか2つ)

これは、新しいことを学ぼうとするときに私が見つけた最大の要因です。ドキュメントの品質であり、ではありません。数時間かかったので、スレッドにビジネスを実行させる方法を心配するのではなく、実際の作業に戻りました。

[〜#〜] edit [〜#〜]実際、Rob KennedyはここでBeginThreadを説明する素晴らしい仕事をしています BeginThread Structure-Delphi

[〜#〜] edit [〜#〜]実際にはRob Kennedyが同じ投稿でTThreadを説明しているように、コードを次のように変更すると思います明日はTThreadを使用してください。来週はどうなるか誰にも分かりません! (多分AsyncCalls)

1
Sam