質問

私は、本質的に同時ダウンロード マネージャーである Cocoa アプリを構築する最良の方法を頭の中で考え出そうとしています。アプリが通信するサーバーがあり、ユーザーはプルダウンするものの大きなリストを作成し、アプリはそのリストを処理します。(HTTP または FTP を使用していないため、URL 読み込みシステムは使用できません。ソケット接続を介して話します。)

これは基本的に、古典的な生産者と消費者のパターンです。重要なのは、消費者の数が固定されており、持続的であることです。サーバーは開くことができる同時接続の数 (通常は少なくとも 2 つ) に厳しい制限を設定しており、新しい接続を開くにはコストがかかるため、理想的には、アプリの存続期間中、同じ N 個の接続が開かれます。

これにアプローチする 1 つの方法は、N 個のスレッドを作成し、それぞれが接続を「所有」し、リクエスト キューを待機して、リクエスト キューが空の場合はブロックすることです。接続数が決して膨大になることはないため、実際のシステムのオーバーヘッドという点では、これは不合理ではありません。しかし概念的には、Cocoa はより洗練されたソリューションを提供する必要があるように思えます。

使えそうな気がする NSOperationQueue, 、そして電話します setMaxConcurrentOperationCount: 接続数で。次に、ダウンロード リクエストをそのキューに放り込むだけです。しかし、その場合、接続自体を管理する方法がわかりません。(それらをスタックに置き、キューに依存してオーバー/アンダーランが発生しないようにしますか?を投げ込みます ディスパッチセマフォ スタックと一緒に?)

今、私たちは素晴らしい新しい世界にいます。 グランドセントラルディスパッチ, 、これに取り組む他の方法はありますか?GCD の主力機能である同時実行性を動的にスケーリングできる (そして、Apple の推奨事項にも言及されている) ため、一見するとそうは思えません。 プロデューサー/コンシューマー実装の変更)実際には役に立ちません。しかし、私はそれについてほんの表面をなぞっただけです。

編集:

重要な場合に備えて:はい、サーバーとの実際の通信には非同期/ノンブロッキング ソケット API を使用する予定です。したがって、I/O 自体は独自のスレッド上にある必要はありません。私が関心があるのは、作業をキューに入れ、接続が利用可能になったときに接続に (安全に) 実行するメカニズムだけです。

役に立ちましたか?

解決 2

後世のために、他の場所で議論した後、これに対して私が採用すると思う解決策は基本的に次のとおりです。

  • 保留中のダウンロード操作のキューがあり、最初は空です。
  • 開いているすべての接続を含むセットを用意します。最初は空です。
  • アイドル状態のオープン接続の変更可能な配列 (実際にはキュー) を用意します。最初は空です。
  • ユーザーがダウンロード要求を追加すると、次のようになります。
    • アイドル状態の接続の配列が空でない場合は、1 つを削除し、そこにダウンロードを割り当てます。
    • アイドル状態の接続はないが、合計接続数が制限に達していない場合は、新しい接続を開いてセットに追加し、ダウンロードをそれに割り当てます。
    • それ以外の場合は、後でダウンロードできるようにダウンロードをキューに入れます。
  • ダウンロードが完了すると:キューリクエストがある場合は、1つをdequeue 1つにして、接続に渡します。それ以外の場合は、接続をアイドル リストに追加します。

その作業はすべてメインスレッドで行われます。各ダウンロードの結果をデコードする作業は GCD にオフロードされるため、同時実行性の調整を処理でき、メインスレッドを詰まらせることはありません。

新しい接続を開くには時間がかかる場合があるため、新しい接続を作成するプロセスは、実際にはもう少し複雑になる可能性があります (たとえば、ダウンロードをキューに入れ、接続プロセスを開始し、接続が完全に確立されたときにキューから外すなど)。しかし、競合状態の可能性についての私の認識は誇張されていたと今でも思っています。

他のヒント

I/O に CFSocket のノンブロッキング呼び出しを使用している場合、データをコピーしているだけで実際には計算を行っていないため、同時実行の問題は OS に処理させ、すべてメインスレッドで実行する必要があることに私も同意します。

それ以上に、アプリが行う必要がある他の作業は、ダウンロードされるアイテムのキューを維持することだけのようです。いずれかの転送が完了すると、CFSocket コールバックはキュー上の次の項目の転送を開始できます。(キューが空の場合は接続数を減らし、空のキューに何かが追加された場合は新しい転送を開始します。) なぜ複数のスレッドが必要なのかわかりません。

もしかしたら何か重要なことを省略しているかもしれませんが、あなたの説明によると、アプリはCPUバウンドではなくI/Oバウンドであるため、すべての同時実行機能はパフォーマンスへの影響を最小限に抑えながらより複雑なコードを作成するだけです。

すべてメインスレッドで実行します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top