4

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

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

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

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

Grand Central Dispatchというすばらしい新しい世界にいる今、これに取り組む他の方法はありますか? GCD の主力機能である同時実行性を動的にスケーリングする機能 (および、 Changing Producer-Consumer Implementationsに関する Apple の推奨事項で言及されている) は、実際には役に立たないため、一見したところ、そうは思えません。しかし、私はそれについて読むことの表面をかじっただけです。

編集:

重要な場合: はい、サーバーとの実際の通信を行うために、非同期/ノンブロッキング ソケット API を使用することを計画しています。したがって、I/O 自体は独自のスレッドである必要はありません。私が関心を持っているのは、作業を待ち行列に入れ、(安全に) 接続が利用可能になったときにそれを接続に渡す仕組みだけです。

4

2 に答える 2

1

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

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

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

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

于 2009-09-25T16:58:49.420 に答える
0

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

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

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

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

于 2010-08-24T18:38:45.250 に答える