5

是的,我知道。关于这个世界有很多问题和答案,NSOperation但我仍然有一些疑问。我试图用一个两部分的问题来解释我的疑问。它们是相互关联的。

在 SO post nsoperationqueue-and-concurrent-vs-non-concurrent中,Darren写道

“并发”操作本身是并发的;它不需要 NSOperationQueue 为其创建线程。

但是稍微搜索了一下,我发现 a NSOperation,即使它被声明为并发(通过覆盖isConcurrent它返回的方法YES),也可以添加到NSOperationQueue. 这是什么意思?如果我将并发添加NSOperation到队列中,幕后发生了什么?相反,如果我按原样使用并发操作(不将其添加到队列中)会发生什么?

从 Apple doc 中获取的注释很清楚:

...操作队列忽略 isConcurrent 返回的值,并始终从单独的线程调用操作的 start 方法。...一般来说,如果您总是在操作队列中使用操作,则没有理由使它们并发。

然后,我对在NSOperation. 我找到了Dave Dribin的一个很好的教程(并发操作)。我明白了他帖子的整体含义。

您不能使用异步模式(例如使用异步NSURLConnection请求),因为无法调用委托。当main完成时,操作被删除。解决方案是重写start控制操作生命周期的方法......并且处理运行循环可能会很痛苦。

现在,试图理解他的帖子,我怀疑是否需要start在主线程中运行该方法。

- (void)start
{
    if (![NSThread isMainThread])
    {
        [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
        return;
    }

    // other code here...
}

在处理异步 API 时,我们可以在 start 的主线程上开始异步调用,并保持操作运行直到完成。

你能解释一下为什么吗?

先感谢您。

4

2 回答 2

11

在我看来,isConcurrent属性的NSOperation名称令人困惑。它的真正意思是“异步”。也就是说,当它-start被调用时,无论操作是否已经运行完成(异步),它是否会快速返回?还是直到操作运行完成(同步)才返回?

正如Apple的文档所述,当操作排队时这并不重要NSOperationQueue,因为队列在工作线程上调用它,无论如何。如果它是同步的,那么该工作线程将专门用于该操作,直到它完成。如果是异步的,那么-start会在操作完成之前返回,工作线程可以继续做其他工作。

问题是,异步方法如何-start确保操作的工作继续进行?这可能需要产生一个单独的线程来完成这项工作,但这很愚蠢。最好让NSOperationQueue处理线程。

更有可能的是,它使用由外部事件驱动的运行循环源。NSURLConnection在它的异步模式中就是这样的事情。但是,在这种情况下,它必须确保它调度运行循环源的线程 a) 将继续存在,并且 b) 将运行它的运行循环。NSOperationQueue也不能依赖工作线程来做。

同样,您可以为每个此类操作创建自己的线程,专门用于停留并运行其运行循环,但这是不必要的,而且与让操作保持同步并对其进行排队相比,这没有任何优势。

您已经知道将保留并运行其运行循环的一个线程是主线程。因此,通常最好将运行循环源安排在主线程的运行循环上。唯一需要注意的是,为了响应触发运行循环源处理程序的外部事件,您不要在主线程上执行任何长时间运行的工作。因此,例如,当NSURLConnection使用接收到的数据调用您的委托方法时,您不会对该数据进行昂贵的计算 - 或者,如果必须,将该昂贵的计算移至另一个线程。

另一种可能性,一种中间立场,是创建一个您自己的线程作为许多异步操作的工作线程。因此,不是使用主线程或每个操作的线程,而是使用单个线程,其工作只是停在其运行循环中。您的所有异步操作都会在该线程的运行循环中自行安排。不过,这种方法并没有太多需要或优势。

于 2012-06-02T15:54:15.180 回答
1

我认为 Dave 在帖子中解决了他将 start 方法分流到主线程的动机:

2009-09-13 更新:从 10.6 起不再适用。从 10.6 开始,总是在后台线程上调用 start 方法。要在仅主线程和依赖运行循环的异步 API 上正常工作,我们需要将工作分流到主线程。更多关于此的后续帖子。

于 2012-06-02T15:15:16.737 回答