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;
  }
}

usleepsched_yield“足够好”吗?那里有一个“好”的号码可以睡觉usleep

(另外:是的,因为这是在我自己的线程中运行的,所以我可以阻止CFReadStreamRead- 这很好,但我也试图阻止上传进度和下载进度,所以阻止那里没有帮助...... )。

任何见解将不胜感激 - 谢谢!

4

2 回答 2

4

我认为这个问题有点自相矛盾,因为你问的是做一些本质上不是最佳实践的事情的最佳实践是什么;)

当有一种非常好的方法来阻止网络 I/O 时,任何导致您轮询的妥协都不是最佳实践。

也就是说,如果您进行民意调查,我认为在您的线程上“运行 runloop 直到日期”可能更合适,而不是使用您想象的任何 posix sleep 或 yield 方法。请记住,每个线程都有自己的 runloop,因此基本上通过运行 runloop,您可以让 Apple 使用其最佳实践的概念来阻塞直到未来的日期。

至于时间延迟,我不知道你是否会得到一个确定的答案,什么是好时光。这是在轮询周期与 CPU 之间的权衡与当 I/O 准备好从网络读取时卡在 runloop 中一会儿。

理想情况下,我认为我会将您的精力重新集中在使用 I/O 阻塞调用来完成这项工作上,但是如果您坚持使用 poll & idle 技术,请不要太担心具体的延迟时间。只需选择有效且似乎不会对任一方向的性能产生负面影响的东西即可。

(另外,我想澄清一下,我对轮询与阻塞的事情并不太虔诚,我只是强调它的价值,因为你显然在寻找一个更高的解决方案)。

于 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 回答