3

CFReadStream現在、を使用して新しいデータをポーリングしていCFReadStreamHasBytesAvailableます。

(最初に、いくつかの背景:私は独自のスレッド化を行っており、runloopのものを台無しにする必要はないので、クライアントコールバックのものは実際にはここでは適用されません)。

私の質問は:ポーリングのために受け入れられている慣行は何ですか?

この件に関するAppleのドキュメントはあまり役に立たないようです。

彼らは「あなたが待っている間に何か他のことをする」ことを勧めます。私は現在、次のようなことをしています。

while(!done)
{
  if(CFReadStreamHasBytesAvailable(readStream))
  {
    CFReadStreamRead(...) ... bla bla bla
  } else {
    usleep(3600); // I made this up
    sched_yield(); // also made this up
    continue;
  }
}

usleepとはsched_yield「十分」ですか?そこに眠るのに「良い」数がありusleepますか?

(また:はい、これは私自身のスレッドで実行されているので、ブロックすることができますCFReadStreamRead-これは素晴らしいことですが、アップロードの進行状況とダウンロードの進行状況を妨害しようとしているので、そこでブロックしても役に立ちません... )。

どんな洞察も大歓迎です-ありがとう!

4

2 に答える 2

4

本質的にベストプラクティスではないことを行うためのベストプラクティスは何かを尋ねているので、この質問は少し逆説的だと思います;)

ネットワーク I/O をブロックするための完全に優れた方法がある場合、代わりにポーリングする原因となる妥協は、定義上、ベスト プラクティスではありません。

とはいえ、ポーリングを行う場合は、想像しているposix sleepまたはyieldメソッドを使用する代わりに、スレッドで「実行ループを日付まで実行する」方が適切であると思います。各スレッドは独自の実行ループを取得することを忘れないでください。基本的に、実行ループを実行することで、Apple は将来の日付までブロックするためのベスト プラクティスの概念を採用できるようになります。

時間の遅れに関しては、あなたが良い時間とは何かについて決定的な答えが得られるかどうかはわかりません. これは、CPU をポーリング サイクルで処理することと、ネットワークから I/O を読み取る準備ができたときに、しばらく実行ループでスタックすることとの間のトレードオフです。

理想的には、I/O ブロッキング呼び出しを使用してこの作業を行うことに再度集中することをお勧めしますが、ポーリングとアイドルの手法に固執する場合は、特定の遅延時間についてあまり心配しないでください。機能し、どちらの方向にもパフォーマンスに悪影響を与えないように見えるものを選択してください。

(また、私はポーリングとブロッキングのことについてあまり宗教的ではないことを明確にしたいと思います。あなたは明らかに高度な解決策を探しているので、その価値を強調しているだけです)。

于 2009-03-01T02:47:09.067 に答える
1

別のスレッドで手動の CFStream ベースの接続を行う場合 (帯域幅の監視やスロットリングなどのカスタム用)、CFReadStreamScheduleWithRunLoop、CFRunLoopRunInMode、および CFReadStreamSetClient を組み合わせて使用​​します。基本的に、0.25 秒間実行してから、ストリームのステータスを確認します。クライアント コールバックも独自に通知されます。これにより、読み取りステータスを定期的にチェックし、いくつかのカスタム動作を実行できますが、主に (ストリーム) イベントに依存しています。

static const CFOptionFlags kMyNetworkEvents =
kCFStreamEventOpenCompleted
| kCFStreamEventHasBytesAvailable
| kCFStreamEventEndEncountered
| kCFStreamEventErrorOccurred;

static void MyStreamCallBack(CFReadStreamRef readStream, CFStreamEventType type, void *clientCallBackInfo) {
    [(id)clientCallBackInfo _handleNetworkEvent:type];
}


- (void)connect {
  ...

  CFStreamClientContext streamContext = {0, self, NULL, NULL, NULL};
  BOOL success = CFReadStreamSetClient(readStream_, kMyNetworkEvents, MyStreamCallBack, &streamContext);


  CFReadStreamScheduleWithRunLoop(readStream_, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);

  if (!CFReadStreamOpen(readStream_)) {
    // Notify error
  }

  while(!cancelled_ && !finished_) {

    SInt32 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.25, NO);

    if (result == kCFRunLoopRunStopped || result == kCFRunLoopRunFinished) {
      break;
    }

    if (([NSDate timeIntervalSinceReferenceDate] - lastRead_) > MyConnectionTimeout) {
      // Call timed out
      break;
    }

    // Also handle stream status CFStreamStatus status = CFReadStreamGetStatus(readStream_);
    if (![self _handleStreamStatus:status]) break;
  }

  CFRunLoopStop(CFRunLoopGetCurrent());


  CFReadStreamSetClient(readStream_, 0, NULL, NULL);
  CFReadStreamUnscheduleFromRunLoop(readStream_, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);

  CFReadStreamClose(readStream_);       

}


- (void)_handleNetworkEvent:(CFStreamEventType)type {
    switch(type) {
        case kCFStreamEventOpenCompleted:
            // Notify connected
            break;

        case kCFStreamEventHasBytesAvailable:
            [self _handleBytes];
            break;

        case kCFStreamEventErrorOccurred:
            [self _handleError];
            break;

        case kCFStreamEventEndEncountered:
            [self _handleBytes];
            [self _handleEnd];
            break;

        default:
          Debug(@"Received unexpected CFStream event (%d)", type);
            break;
    }
}
于 2009-10-14T22:26:16.850 に答える