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

Cen*_*ion 31 concurrency multithreading objective-c grand-central-dispatch ios

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

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

[NSThread detachNewThreadSelector:@selector(myMethod:) toTarget:self withObject:_myParamsArray];
Run Code Online (Sandbox Code Playgroud)

b)使用简单的快捷方式(从iOS 2.0开始提供).可从继承的NSObject获得,但该方法也属于NSThread类:

[self performSelectorInBackground:@selector(myMethod:) withObject:_myParamsArray];
Run Code Online (Sandbox Code Playgroud)

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

dispatch_async(dispatch_get_global_queue(0, 0),
  ^ {
      [self myMethod:_myParamsArray];
    });
Run Code Online (Sandbox Code Playgroud)

d)不知何故,使用一些类,如NSOperation,NSBlockOperation或NSOperationQueue,虽然不确定如何完成它(一些例子将被赞赏)

目前,我使用了案例"b",但对其利弊和其他相关建议充满好奇.

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

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

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

更新2:已经有一些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....
Run Code Online (Sandbox Code Playgroud)

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

Mac*_*ade 25

通常,您更喜欢GCD方法.

在同步/锁定方面比纯线程(NSThread - pthread)更简单,并且在性能方面可能更准确.

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

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

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

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

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

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

希望对你有帮助 : )

编辑

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

编辑2

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

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

参考

所有这些都在" 并发编程指南"中得到了很好的解释.它讨论了GCD和线程方法,以及有关使用和实现的大量细节.

如果你还没有读过,你应该看看.