2011-11-06 10 views
0

ウェブページのソースをメモのコンポーネントにダウンロードする最も速い方法は何ですか?私はIndyコンポーネントとHttpCliコンポーネントを使用します。もっと速くダウンロードするには?

問題は、リストボックスに100以上のサイトがあり、私のプログラムがソースをメモにダウンロードし、そのソースをmp3ファイルとして解析していることです。それはGoogleの音楽検索プログラムのようなものです。それはGoogleの検索をより簡単にするためにGoogleのクエリを使用します。

私の質問につながるスレッドについて読み始めました。解析機能を持つスレッドでIdHttpインスタンスを作成し、リストボックスの半分のサイトを解析するように指示できますか?

だから、基本的にユーザーがクリックを解析する際に、メインスレッドが実行する必要があります。

for i := 0 to listbox1.items.count div 2 do 
    get and parse 
、そして他のスレッドが実行する必要があります。

for i := form1.listbox1.items.count div 2 to form1.listbox1.items.count - 1 do 
    get and parse. 

をので、彼らがでform1.listbox2に解析されたコンテンツを追加します同じ時間。または、メインスレッドで2つのIdHttpインスタンスを開始する方が簡単かもしれません。 1つはサイトの前半、もう1つは第2のサイトですか?

これについて:私はIndyかSynapseを使用しますか?

+0

私はあなたがSynchronizeが何をしているかについてのドキュメントを読んで、それぞれのスレッドが開始するときに、そしてeachが1つのURLを処理するたびに1つのURLだけを要求するよう勧めます。 WebサイトがXHTMLを使用している場合、MSXML2_TLBのDOMDocument.loadメソッドをチェックして、読み込みと解析がうまく機能するかどうかを確認します。 –

答えて

9

私は、1つのURLを読み取り、その内容を処理できるスレッドを作成します。それで、同時に発射するスレッドの数を決めることができます。あなたのコンピュータはかなりの数の接続を許可するので、100のサイトが異なるホスト名を持つ場合、同時に10または20を実行することは問題ではありません。あまりにも多くのことは過剰ですが、あまりにも少ないプロセッサ時間の浪費です。

ダウンロードと処理のために別々のスレッドを用意することで、このプロセスをさらに調整することができます。これにより、多数のスレッドがコンテンツを絶えずダウンロードできるようになります。ダウンロードはあまりプロセッサーを必要としません。基本的にはレスポンスを待っているので、比較的多数のダウンロードスレッドを簡単に持つことができます。他のワーカースレッドは結果のプールからアイテムを取得して処理できます。
ダウンロードと処理を分割すると少し複雑になりますが、あなたはまだその課題にはつながらないと思います。

現在、いくつかの問題があります。最初は、スレッド内でVCLコンポーネントを使用することはできません。スレッドのリストボックスからの情報が必要な場合は、メインスレッドへの安全な呼び出しを行うためにスレッド内で同期を使用するか、スレッドを開始する前に必要な情報を渡す必要があります。後者のほうが効率的です。なぜなら、Synchronizeを使用して実行されたコードが実際にメインスレッドで実行されるため、マルチスレッドの効率が低下するからです。

しかし私の注意は実際には最初の行に "メモのコンポーネントにウェブページのソースをダウンロード"と書いてありました。それをしないでください!それらの結果をメモに書き込んで処理しないでください。自動処理は、ビジュアルコントロールの外で、メモリ内で行うのが最適です。テキストを処理するために文字列、ストリーム、または文字列リストを使用することは、メモを使用するよりも高速です。
文字列リストにもいくつかのオーバーヘッドがありますが、同じ索引付け構造(メモのLinesプロパティであるTMemoStringsとTStringListの両方に同じ祖先があります)を使用しています。 TStringListに変換するのは非常に簡単です。

+2

Downvoter、あなたはあなたが間違っていると思う動機を与えてくださいできますか? – GolezTrol

+0

+1の良いアプローチと、メモコントロールを使用することが悪い考えであることを指摘してくれてありがとう。私は非常に素敵なスレッドセーフな文字列リストを見つけました。これは便利です(Tilo EckertのTThreadStringList): http://www.swissdelphicenter.ch/torry/showcode.php?id=2167 TStringListのラッパーですクリティカルセクションを使用して基礎となる文字列リストへの安全なアクセスを保証します。 –

+0

ダウンロードするアイテムのリストにTThreadStringListを使用するのは本当に便利です。ダウンロードされた各アイテムは、処理のために別々のTThreadStringListにプッシュできます。そうすれば、あまりにも面倒なく、私が示唆したように、ダウンロードと処理を分けることができます。 – GolezTrol

5

私はすべてのスレッドの解析を行うことをお勧めします。メインスレッドは何も解析しません。メインスレッドはUIを管理するだけです。 TMemoからHTMLを解析せず、各スレッドをTStreamまたはStringにダウンロードさせてから直接解析します。 TIdSyncまたはTIdNotifyを使用して解析結果をUIに送信して表示します(速度が重要な場合はTIdNotifyを使用します)。解析ロジックにUIコンポーネントを含めることで、その処理速度が遅くなります。

+1

パーサが構文解析だけでなく、データ処理を行っている場合、パーサは100%マルチスレッドセーフではない可能性があります。 IMHOの解析はダウンロードよりもはるかに高速です。 –

+0

リストボックスで%20、%3Dなどを置き換えるだけで、ダウンロードして解析することができますし、stringreplace ... –

+0

最終結果が表示される準備が整うまで、UIは関与せずにすべてを行うことができます。各スレッドがStringまたはTMemoryStream(TIdHTTPは両方をサポート)にダウンロードし、データを解析し、結果をTIdNotifyを使用してメインスレッドにポストするリストエントリの必要に応じてスレッドを生成し、TStringListにURLを収集します。これはスレッドセーフであり、不要なUIのボトルネックを回避します。 –

4

IndyまたはSynapseはどちらもマルチスレッド対応です。私はIndyよりはるかに軽いSynpaseを使用することをお勧めしますし、あなたの目的に十分に十分でしょう。マイクロソフトが提供するHTTP APIsを忘れないでください。

シンプルな実装:URIあたり

  • 1つのスレッド。
  • 各スレッドは1つのHTTP通信を使用してデータを取得します。
  • 各スレッドはデータを解析します。
  • 次に、Synchronizeを使用してUIを更新します。

おそらく私のお気に入り:

  • (例えば8)を使用する最大スレッド数を定義します。
  • これらのスレッドはそれぞれ、リモート接続を維持します(これはHTTP/1.1の目的であり、実際には速度を変えることができます)。
  • すべてのリクエストは、スレッドごとに1つずつ取得されます。スレッドに事前割り当てはしませんが、スレッドが完了するとグローバルリストから新しいURLを取得します(各URLは常に同じ時間をとるわけではありません)。
  • スレッドは、(例えば、Sleep(100)またはセマフォを使用して)他のURIがグローバルリストに追加されるまで待つことができます。
  • 次に、専用のGDIメッセージ(WM_USER+...)を使用して、メインGUIスレッドのUIを解析して更新します。解析は高速IMHです(UIリフレッシュが遅くなる可能性があることを覚えておいてください)。たとえば、BeginUpdate-EndUpdateメソッドバックグラウンドスレッドをブロックするSynchronizeを使用するよりも、関連するHTMLデータを持つGDIメッセージが効率的であることが分かりました。
  • もう1つの方法は、URIからデータを取得した直後にバックグラウンドスレッドで解析することです(パーサーが遅い場合のみ)。パーサーであればマルチスレッドの問題になるかもしれません/データプロセッサはスレッドセーフではありません。

第2は、いわゆる「ダウンロードマネージャ」の実装方法です。

マルチスレッドを扱うときは、共有リソース(リストなど)を「保護」する必要があります。 TCriticalSectionを使用して、グローバルリスト(URIリストなど)にアクセスし、できるだけ早くロックを解除してください。

複数のコンピュータとネットワーク、同時アクセス、さまざまなオペレーティングシステムで実装をテストしてみてください。マルチスレッドアプリケーションのデバッグは難しいかもしれませんので、よりシンプルな実装ほど良いでしょう。ダウンロードパートをマルチスレッドにすることを推奨しますが、メインスレッドがデータを処理するようにするのはなぜですか?早くして)。

+0

リストからURLを取得する方法を私に簡単なコードで教えてもらえますか?100個のURLをリストボックスから8個のスレッドに分割する方法がわからないので...私は変数リンクを作成してthread.resumeの前にスレッドに送ります –

+1

@DanijelMaksimovicMaxa URIは単なるグローバルな 'TStringList'であり、新しいファイルを自由にダウンロードできるときはすべてのスレッドから読み込まれます。あなたは*スレッドにURIを割り当てませんが、ダウンロードされる残りのURIについてスレッドにリストを要求させます。 TCriticalSectionでリストへのアクセスを保護する必要があります。これにより、2つのスレッドが同じURIを一度に取得しないようにすることができます。 –

関連する問題