在单独的线程上调用我的方法有哪些不同的方法?

时间:2011-11-28 11:16:03

标签: objective-c ios multithreading concurrency grand-central-dispatch

我有一些数据计算方法(让它成为“myMethod:”),我想将调用移到另一个线程,因为我不想阻止我的主UI功能。所以,开始研究如何在另一个线程上调用我的方法。据我所知,目前有很多不同的方法可以做到这一点。这是一个清单:

a)使用纯线程(自iOS 2.0起可用):

[NSThread detachNewThreadSelector:@selector(myMethod:) toTarget:self withObject:_myParamsArray];

b)使用简单的快捷方式(自iOS 2.0起可用)。可从继承的NSObject获得,但该方法也属于NSThread类:

[self performSelectorInBackground:@selector(myMethod:) withObject:_myParamsArray];

c)使用Grand Central Dispatch队列的新方法(自iOS 4.0起可用):

dispatch_async(dispatch_get_global_queue(0, 0),
  ^ {
      [self myMethod:_myParamsArray];
    });

d)不知何故,使用一些类,如NSOperation,NSBlockOperation或NSOperationQueue,虽然不确定如何做到这一点(一些例子将不胜感激)

目前,我已经使用了案例“b”但对其利弊及其他相关建议感到好奇。

更新:e)还找到了另一种执行类似线程的方法 - Run loops。以下是苹果文档的摘录:

  

运行循环是一个事件处理循环,用于计划工作并协调传入事件的接收。运行循环的目的是在有工作时保持线程忙,并在没有线程时让线程进入休眠状态。

恕我直言,或多或少你正在处理相同的任务 - 如何在单独的线程上调用你的方法进行异步操作。

UPDATE2:已经有一些NSInvocationOperation和NSOperationQueue和恕我直言的经验,这是非常方便的。根据Apple文档,GCD和NSOperations是实现多线程的首选方式。此外,NSOperations从iOS 4.0开始在GCD上运行。简而言之,您实例化NSIvocationOperation(作为对您的方法的调用)然后实例化NSOperationQueue并将调用添加到队列。 NSOperationQueue足够聪明,你可以实例化多个NSIvocationOperation对象(包装方法调用)并将它们实例化为NSOperationQueue。其余的都有保证。 NSOperationQueue确定执行调用所需的并行线程数(NSInvocationOperation)并为您处理。它可以在线程A上执行第一次调用,然后在线程B上执行第二次调用,在线程C上执行第三次,在线程B上执行第三次调用,因此您不必担心这一点。但是如果你愿意,你可以告诉NSOperationQueue最大线程如何用于执行调用(例如1),但我没有必要这样做。默认情况下,所有任务都在主线程以外的位置执行,因此默认情况下操作队列是异步的。此外,如果要在严格队列中执行方法调用(每个包装在单独的NSInvocationOperation中),则可以添加依赖项,因此NSOperationQueue将保留方法调用顺序。这是一个例子:

// wrap your method call into NSInvocationOperation object
NSInvocationOperation *currentOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(yourMethodCall) object:nil];

// _sharedOperationQueue is a shared NSOperationQueue 
// get all executing operations from the queue and get the last operation
_lastOperation = [[_sharedOperationQueue operations] lastObject];

// check if _lastOperation is not nil
if (_lastOperation) {

    // if not then add dependency, so the calls would be performed in a queue
    [currentOperation addDependency:_lastOperation];
}

// say - execute my method (operation)
[_sharedOperationQueue addOperation:currentOperation];

_lastOperation = currentOperation; // mark as last operation for adding dependency to the next operation

// the queue will retain invocation operation so you will release
[currentOperation release];

 ..... you can create another NSInvocationOperation and add it to the queue....

对于RUNLOOP,有时您会面对它们,例如在启动/安排计时器或进行NSURL连接时。恕我直言,可以将runloop与在一个线程上执行的任务队列进行比较。恕我直言,runloop是指向作为队列运行的线程的指针:它具有可能抛出事件的任务,并且它们将被放置在该线程的队列末尾。默认情况下,应用程序中的所有任务都在单个运行循环中运行 - 在单个线程中。我说这是一个指针,因为当你的应用程序生成事件时,应用程序必须知道将该事件(触摸事件或其他委托回调)放在何处执行。当然,你应该阅读有关更多详细信息的runloops,因为这些只是我的想法。

2 个答案:

答案 0 :(得分:25)

通常,您更喜欢GCD方法。

同步/锁定比纯线程(NSThread - pthread)更简单,从性能角度来看可能更准确。

使用纯线程时,问题是您可能会遇到性能问题,具体取决于可用内核/处理器的数量。

例如,如果您只有一个核心,那么创建多个线程可能会降低您的应用程序速度,因为CPU将花费大部分时间从一个线程切换到另一个线程,从而节省堆栈,寄存器等。

另一方面,如果你有很多可用的核心,那么创建很多不同的线程可能会很不错。

这是GCD帮助的地方,因为它为您管理。它将根据可用的系统资源创建适当数量的线程,以确保最佳利用率,并适当地安排您的操作。

但是,出于这个原因,使用GCD启动的任务可能不是实时的。

因此,如果您真的需要立即运行分离任务,请使用显式线程。否则,请使用GCD。

希望这会对你有所帮助:)。

修改

关于performSelectorInBackground的说明:它只是创建一个新线程。因此,与NSThread方法基本没有区别。

编辑2

NSOperation相关的东西有点不同。在Mac OS X上,它们是从版本10.6开始使用GCD实现的。以前的版本使用线程。

在iOS上,它们仅使用线程实现。

<强>参考

所有这些都在Concurrency Programming Guide中得到了很好的解释。它讨论了GCD和线程方法,以及有关使用和实现的大量细节。

如果你还没有看过,你应该看看。

答案 1 :(得分:0)

这是旧问题的更新答案。现在使用libdispatch为macos和ios实现NSOperations。他们已经有一段时间了。调用不同线程的首选方法是使用libdispatch或NSOperations之一。要记住的主要思想是“服务质量”或“QOS”。 QOS是分配给线程的东西,当你将它分配给一个调度队列,NSOperationQueue或一个NSOperation时,你实际上是在说“我希望这个在分配了这个QOS的线程上运行”。特例是主线程。

可能仍有一些使用NSThread的情况,但我很长时间都没有。