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

Posted

技术标签:

【中文标题】在单独的线程上调用我的方法都有哪些不同的方法?【英文标题】:What are the different ways for calling my method on separate thread?在单独的线程上调用我的方法有哪些不同的方法? 【发布时间】:2011-11-28 11:16:02 【问题描述】:

我有一些数据计算方法(让它成为“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 queues 的新方法(自 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 是指向作为队列运行的线程的指针:它具有可能引发事件的任务,它们将被放置在该线程中队列的末尾。默认情况下,您的应用程序中的所有任务都在单个 runloop 中运行 - 在单个线程中。我说它是一个指针,因为当您的应用程序生成事件时,应用程序必须知道将该事件(触摸事件或其他委托回调)放置在何处以执行。当然,您应该阅读有关运行循环的更多详细信息,因为这些只是我的想法。

【问题讨论】:

【参考方案1】:

通常,您更喜欢 GCD 方法。

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

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

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

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

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

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

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

希望这对你有帮助:)

编辑

关于performSelectorInBackground 的注释:它只是创建了一个新线程。所以和 NSThread 的方式基本没有区别。

编辑 2

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

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

参考

所有这些都在Concurrency Programming Guide 中得到了很好的解释。它讨论了 GCD 和线程方法,并详细介绍了使用和实现。

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

【讨论】:

【参考方案2】:

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

可能还有一些使用NSThread的情况,但是我已经很久没有使用了。

【讨论】:

这可能更适合作为对上一个答案的评论,但我仍然习惯于 *** 礼仪。

以上是关于在单独的线程上调用我的方法都有哪些不同的方法?的主要内容,如果未能解决你的问题,请参考以下文章

在多线程中,子线程更新主线程ui都有哪些方法及注意点

线程的状态都有哪些

如何在 Java 中调用具有单独线程的方法?

在单独的线程中调用 MFC UI 类上的方法

C#在不同线程的同一类中的父线程中调用方法

用于线程处理的类都有哪些