我有一个应用程序,我从网络下载了大量资源,并对每个资源进行了一些处理。我不希望这个工作发生在主线程上,但是它非常轻量级且低优先级,因此所有这些都可以在同一个共享工作线程上发生。这似乎是一件好事,因为设置和安装所需的工作。拆除所有这些工作线程(其中没有一个会长寿,等等。)
但令人惊讶的是,似乎没有一种简单的方法可以在单个共享线程上完成所有这些工作,而不是为每个任务生成新线程。由于多年来似乎已经出现了大量实现并发的途径,这一点变得复杂。 (明确NSThreads
,NSOperationQueue
,GCD等。)
我是否高估了产生所有这些线程所涉及的开销?我是不是应该不流汗,并使用更简单的每线程任务方法?使用GCD,并假设它比线程(重新)使用更聪明?
答案 0 :(得分:8)
使用GCD - 这是目前的官方建议,它比任何其他解决方案都要少。如果您明确需要传递的内容以串行方式发生(即,就像在单个线程上一样),那么您可以实现这一点,但是改变可能更聪明,例如。
[self doCostlyTask];
要:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^()
{
[self doCostlyTask];
dispatch_async(dispatch_get_main_queue(), ^()
{
// most UIKit tasks are permissible only from the main queue or thread,
// so if you want to update an UI as a result of the completed action,
// this is a safe way to proceed
[self costlyTaskIsFinished];
});
});
这基本上告诉操作系统“在低效率的情况下执行此代码,无论哪种方式最有效”。您发布到任何全局队列的各种内容可能会也可能不会在彼此相同的线程上执行,也可能作为调度它们的线程执行,并且可能会或可能不会同时发生。操作系统应用它认为最优的规则。
博览会:
GCD是Apple的线程池实现,他们同时引入了闭包(作为“块”)以使其可用。所以^(C-style args){code}
语法是一个块/闭包。也就是说,它的代码加上代码引用的任何变量的状态(受制于警告)。您可以在没有GCD知识或使用的情况下自行存储和调用块。
dispatch_async
是一个GCD函数向指定队列发出一个块。它在某个时间执行某个线程上的块,并应用未指定的内部规则以最佳方式执行此操作。它会根据诸如您拥有多少内核,每个内核有多忙,目前正在考虑节能(可能取决于电源),特定CPU的电源成本如何计算等因素来判断。
因此,就程序员的开发而言,块会将代码转换为可以作为参数传递的代码。 GCD允许您根据操作系统可以管理的最佳调度请求执行块。块的创建和复制非常轻巧 - 比例如NSOperation
秒。
GCD超越了上述示例中的基本异步调度(例如,您可以执行并行for循环并等待它在单个调用中完成)但除非您有特定需求,否则它可能并非完全相关。
答案 1 :(得分:4)
但令人惊讶的是,似乎没有一种简单的方法可以获得所有 这项工作发生在一个共享线程上,而不是 为每个任务产生一个新线程。
这正是GCD的用途。 GCD维护着一个可用于执行任意代码块的线程池,它负责管理该池,以便在手头的任何硬件上获得最佳结果。这样可以避免不断创建和销毁线程的成本,还可以避免必须确定可用的处理器数量等等。
如果您真的关心只应该使用一个线程,Tommy会提供正确的答案,但听起来您实际上只是想避免为每个任务创建一个线程。
实现这一目标的道路很多,这很复杂 似乎多年来出现的并发性。 (显式 NSThreads,NSOperationQueue,GCD等。)
NSOperationQueue uses GCD,如果它比直接使用GCD更容易,那么你可以使用它。
使用GCD,并假设它比线程(重新)使用更聪明?
完全。
答案 2 :(得分:1)
我会使用NSOperationQueue或GCD和个人资料。无法想象线程开销会击败网络延迟。
NSOperationQueue会让你限制同时操作的次数,如果他们最终变得太贪心了。实际上,如果需要,可以将其限制为一个。