使用单个共享后台线程进行 iOS 数据处理?
我有一个应用程序,可以从网络下载大量资源,并对每个资源进行一些处理。我不希望这项工作发生在主线程上,但它非常轻量级且优先级低,因此所有这些工作都可以真正发生在同一个共享工作线程上。这似乎是一件好事,因为设置和安装所需的工作量很大。拆除所有这些工作线程(它们都不会存活很长时间,等等)。
但令人惊讶的是,似乎没有一种简单的方法可以让所有这些工作在单个共享线程上进行,而不是为每个任务生成一个新线程。由于多年来出现的大量实现并发的途径,情况变得更加复杂。 (显式 NSThreads、NSOperationQueue、GCD 等)
我是否高估了生成所有这些线程所涉及的开销?我是否应该不费力气,而使用更简单的每任务线程方法?使用 GCD,并假设它在线程(重新)使用方面比我更聪明?
I have an app where I'm downloading a number of resources from the network, and doing some processing on each one. I don't want this work happening on the main thread, but it's pretty lightweight and low-priority, so all of it can really happen on the same shared work thread. That seems like it'd be a good thing to do, because of the work required to set up & tear down all of these work threads (none of which will live very long, etc.).
Surprisingly, though, there doesn't seem to be a simple way to get all of this work happening on a single, shared thread, rather than spawning a new thread for each task. This is complicated by the large number of paths to achieving concurrency that seem to have cropped up over the years. (Explicit NSThreads
, NSOperationQueue
, GCD, etc.)
Am I over-estimating the overhead involved in spawning all of these threads? Should I just not sweat it, and use the easier thread-per-task approaches? Use GCD, and assume that it's smarter than I about thread (re)use?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用 GCD — 这是当前的官方建议,并且比任何其他解决方案都更省力。如果您明确需要传入的内容连续发生(即,就像在单个线程上一样),那么您可以实现这一点,但更改可能更聪明,例如
:
这本质上告诉操作系统“以低优先级执行此代码只要是最有效率的地方就可以做到这一点”。您发布到任何全局队列的各种事物可能会也可能不会在彼此以及分派它们的线程的同一线程上执行,并且可能会也可能不会同时发生。操作系统应用它认为最佳的规则。
说明:
GCD 是 Apple 的线程池实现,他们同时引入了闭包(作为“块”)以使其可用。因此
^(C-style args){code}
语法是一个块/闭包。也就是说,它是代码加上代码引用的任何变量的状态(根据注意事项)。您可以自己存储和调用块,无需 GCD 知识或使用。dispatch_async
是一个 GCD 函数,向指定队列发出一个块。它有时会在某个线程上执行该块,并应用未指定的内部规则以最佳方式执行此操作。它将根据诸如您有多少个核心、每个核心的繁忙程度、当前对节能的考虑(这可能取决于电源)、特定 CPU 的电源成本如何计算等因素来进行判断。因此,就程序员的发展而言,块将代码变成可以作为参数传递的东西。 GCD 允许您请求根据操作系统可以管理的最佳调度来执行块。块的创建和复制非常轻量——比 NSOperation 等轻得多。
GCD 超越了上面示例中的基本异步调度(例如,您可以执行并行 for 循环并等待它在单个调用中完成),但除非您有特定需求,否则它可能并不那么相关。
Use GCD — it's the current official recommendation and it's less effort than any of the other solutions. If you explicitly need the things you pass in to occur serially (ie, as if on a single thread) then you can achieve that but it's probably smarter just to change, e.g.
To:
That essentially tells the OS "do this code with low priority wherever it would be most efficient to do it". The various things you post to any of the global queues may or may not execute on the same thread as each other and as the thread that dispatched them and may or may not occur concurrently. The OS applies the rules it considers optimal.
Exposition:
GCD is Apple's implementation of thread pooling, and they introduced closures (as 'blocks') at the same time to make it usable. So the
^(C-style args){code}
syntax is a block/closure. That is, it's code plus the state of any variables (subject to caveats) that the code references. You can store and call blocks yourself with no GCD knowledge or use.dispatch_async
is a GCD function issues a block to the nominated queue. It executes the block on some thread at some time, and applies unspecified internal rules to do so in an optimal fashion. It'll judge that based on factors such as how many cores you have, how busy each is, what it's currently thinking on power saving (which may depend on power source), how the power costs for that specific CPU work out, etc.So as far as the programmer is developed, blocks make code into something you can pass around as an argument. GCD lets you request that blocks are executed according to the best scheduling the OS can manage. Blocks are very lightweight to create and copy — a lot more so than e.g.
NSOperation
s.GCD goes beyond the basic asynchronous dispatch in the above example (eg, you can do a parallel for loop and wait for it to finish in a single call) but unless you have specific needs it's probably not all that relevant.
这正是 GCD 的用途。 GCD 维护一个线程池,可用于执行任意代码块,并且它负责管理该线程池,以便在任何现有硬件上获得最佳结果。这避免了不断创建和销毁线程的成本,也使您不必弄清楚有多少处理器可用等。
如果您真的关心只应该使用单个线程,Tommy 提供了正确的答案,但听起来像您实际上只是想避免为每个任务创建一个线程。
NSOperationQueue 使用 GCD,因此您可以使用它如果它比直接使用 GCD 让生活更轻松。
确切地。
This is exactly what GCD is for. GCD maintains a pool of threads that can be used for executing arbitrary blocks of code, and it takes care of managing that pool for best results on whatever hardware is at hand. This avoids the cost of constantly creating and destroying threads and also saves you from having to figure out how many processors are available, etc.
Tommy provides the right answer if you really care that only a single thread should be used, but it sounds like you're really just trying to avoid creating one thread per task.
NSOperationQueue uses GCD, so you can use that if it makes life easier than using GCD directly.
Exactly.
我会使用 NSOperationQueue 或 GCD 和配置文件。无法想象线程开销会击败网络延迟。
NSOperationQueue 可以让你限制同时操作的数量,如果它们最终变得太贪婪的话。事实上,如果需要,您可以将其限制为一个。
I would use NSOperationQueue or GCD and profile. Can't imagine thread overhead will beat out network delays.
NSOperationQueue would let you limit the number of simultaneous operations, if they end up getting too greedy. In fact, you can limit it to one if you need to.