问题描述
此问题与操作队列和调度队列之间的区别无关.我知道.我经历了它.
但请记住,我没有任何这样的例子,我可以100%说,是的,GCD应该是唯一的选择.或OperationQueue应该是完美的选择.
您能给我一个例子,解释一个明显高于另一个的优先级吗?
因为几乎所有可以由gcd完成的事情,也可以由操作队列完成.
没有100%的价格,但是在某些情况下,您可能更喜欢一种:
作为一般规则,您可能会喜欢GCD,因为它效率更高.话虽如此,在以下情况下,人们可能会喜欢Operation
:
-
您通过封装
Operation
来包装本身是异步的任务(例如,网络请求).例如,试图理解异步操作子类.
-
您希望将某些操作的逻辑封装在其自己的对象中,以提供更好的职责分离.
例如,假设我要在用户界面中显示一堆图像,并且想要异步调整它们的大小.我不想让异步调整大小逻辑妨碍我的视图控制器(或视图或视图模型/演示者).我可以将异步调整大小的逻辑包装在其自己的
Operation
子类中. -
您想要并发,但也想限制在任何给定时间可以完成多少次.
例如,如果要处理许多图像,您可能不想说在任何给定时间都不想做多于4张图像,因为您想在任何给定时间限制峰值内存使用量.因此,您需要设置
OperationQueue
的maxConcurrentOperationCount
. -
虽然可以同时取消GCD
DispatchWorkItem
对象和Operation
对象,但Operation
中的实现更为优雅.例如,假设我有一个包装异步网络请求的
Operation
.我可以编写自己的cancel
覆盖,这将取消网络请求.如果您的任务由某些for
或while
循环组成,则可以使用DispatchWorkItem
取消操作(例如如何停止DispatchWorkItem (在GCD中)?),但是在处理本身是异步的任务时,Operation
可以更好地处理此问题.但是,即使在简单的场景中,我也发现在操作队列中进行取消更为简单和直观. -
操作队列非常适合那些您可能具有复杂依赖性的情况.
例如,您有任务A,B,C,D和E,但是您不希望C和D在A和B完成后才能运行,而您只希望E在C和D时运行完成.操作队列可以通过依赖项"很好地处理这类情况.
-
您的队列中有很多任务,但是它们的优先级不同.使用操作队列,每个任务可以具有自己的
queuePriority
和操作队列将倾向于优先选择那些优先级较高的操作,而不是优先级较低的操作.
其中一些方法也可以在GCD中实现,但是在这些情况下,操作队列可能更适合.
话虽如此,在某些情况下,GCD绝对更适合:
-
我想要与某些对象进行线程安全的交互.进行同步时,我需要尽可能少的开销.
例如,您可以将读取器-写入器模式与GCD并发队列一起使用.然后,使用
sync
相对于彼此并发执行读取操作,但是使用屏障异步执行写入操作(因此永远不会相对于其他任何操作同时进行写操作). -
我只想快速将一些UI更新发送到主队列.
例如,假设正在运行一个
URLSession
任务,并且在其完成处理程序(在后台串行队列中运行)中,我想更新UI或模型对象.我通常只想达到DispatchQueue.main.async { ... }
.简单高效. -
我想在后台队列上运行计时器.
-
我想使某些计算任务与UI更新脱钩.我可能会进行派遣合并或添加源".
例如,您可能正在做一些复杂的计算,并且想要更新进度指示器,但是更新的速度可能比UI可以处理它们的速度更快.因此,我们可以使用分派添加源将后台任务与UI更新分离.例如,长循环块应用.
-
我有一些计算量大的任务,我想最大限度地利用设备上的内核,但又不想用尽非常有限的GCD工作线程.在这种情况下,我需要联系
concurrentPerform
来并行化for
循环. (请参见前面的示例.)
简而言之(并且要简化),GCD非常适合简单高效的任务(或低级控制),而操作队列则非常适合高级逻辑工作单元.
有关更多信息,另请参见何时使用GCD队列,何时知道您需要它们?
this question is not about what is the difference between operation queues and dispatch queues. i know that. i have gone through it.
but still in mind, i don't have any such example where i can 100% say that, yeah GCD should be only choice for it. or OperationQueue should be perfect choice for it.
can you give me some example, which explains clear priority of one over another?
because almost everything which can be done by gcd, can be also done by operation queue.
Nothing’s 100%, but there are cases where you might prefer one over the other:
As a general rule, you might favor GCD because it is more efficient. That having been said, one might favor Operation
in these scenarios:
You are wrapping a task that, itself, is asynchronous (e.g. a network request), by subclassing
Operation
.For example, Trying to Understand Asynchronous Operation Subclass.
You want to encapsulate the logic of some operation in its own object, offering nicer separation of responsibilities.
For example, let’s say I have a bunch of images that I want to show in my UI, and I want to asynchronously resize them. I don’t want to encumber my view controller (or view, or the view model/presenter) with asynchronous resizing logic. I can wrap that asynchronous resizing logic within its own
Operation
subclass.You want concurrency, but also want to constrain how many can be done at any given moment in time.
For example, if processing many images, you might not want to say that you don’t want to do more than 4 at any given time because you want to limit the peak memory usage at any given moment in time. So you’d set the
maxConcurrentOperationCount
of yourOperationQueue
.While you can cancel both GCD
DispatchWorkItem
objects andOperation
objects, the implementation withinOperation
is a little more elegant.For example, let’s say I have an
Operation
that wraps an asynchronous network request. I can write my owncancel
override that will cancel the network request. If your tasks consists of somefor
orwhile
loop, you can achieve cancelation withDispatchWorkItem
(e.g. How to stop a DispatchWorkItem in GCD?), but when dealing with a task that is, itself, asynchronous,Operation
handles this much better. But even in simple scenarios, I find cancelation within operation queues to be simpler and more intuitive.Operation queues are well suited for those cases where you might have complicated dependencies.
For example, you have tasks A, B, C, D, and E, but you don’t want C and D to run until after A and B are done, and you only want E to run when C and D are done. Operation queues handle these sorts of scenarios well with "dependencies".
You have a queue with lots of tasks, but they are of differing priorities. With operation queues, each task can have its own
queuePriority
and the operation queue will tend to favor those higher priority operations over lower priority ones.
Some of those can be achieved within GCD, too, but these are scenarios in which operation queues might be better suited.
That having been said, there are scenarios where GCD is definitely much better suited:
I want thread-safe interaction with some object. I want as little overhead as possible when doing that synchronization.
For example, you might use the reader-writer pattern with a GCD concurrent queue. Then perform reads concurrently with respect to each other with
sync
, but perform writes asynchronously with a barrier (so they’re never done concurrently with respect to anything else).I just want to quickly dispatch some UI update to the main queue.
For example, let’s say there is a
URLSession
task running and in its completion handler (which runs on a background serial queue), I want to update the UI or model object. I would generally just reach forDispatchQueue.main.async { ... }
. It is simple and efficient.I want to run a timer on a background queue.
For example, see How to execute a method every second on a background thread so it doesn't affect the performance of the app?
I want to decouple some computational task from UI updates. I might reach for a dispatch merge or add "source".
For example, you might be doing some complicated calculation and you want to update a progress indicator, but the updates might come more quickly than the UI can handle them. So we can decouple background tasks from UI updates with dispatch add source. E.g., Long cycle blocks application.
I have some computationally intensive task and I want to maximize my use of the cores on my device, but don’t want to exhaust the very limited number of GCD worker threads. In that case, I’d reach for
concurrentPerform
to parallelize myfor
loop. (See previous example.)
In short (and to oversimplify), GCD is ideally suited for simple and efficient tasks (or low-level control) and operation queues are well suited for high-level logical units of work.
For more information, also see When are GCD queues used and when do you know you need them?
这篇关于寻找一个特定的示例,其中“操作"优于"GCD",反之亦然的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!