AHDispatch 提供了对 Apple 的 Grand Central Dispatch (GCD) 框架的队列节流功能。
AHDispatch 由几个与 GCD 类似的接口组成,可以用来创建节流串行队列,并将其用于异步和同步块任务。
但是 GCD 不是自带了 dispatch_after
调用吗? 是的,它确实有了!如果您需要稍作等待后再执行块操作,那将非常棒。AHDispatch 的出现是为了遵守第三方 API 服务的速率限制规则。AHDispatch 不会使用 dispatch_after
,因此提交到空队列的第一个块将不会受到这种限制(当然,但也有在多核硬件上执行并发代码的常规限制)。
首先,将 AHDispatch.m
和 AHDispatch.h
添加到您的项目中,并导入头文件
#import "AHDispatch.h"
然后,您只需要使用两个 API 调用就可以开始使用:ah_throttle_queue_new
和 ah_throttle_async
。在下面的示例中,我们创建了一个默认节流时间为 0.5 秒的新队列,并向其提交了一个异步执行的块
dispatch_queue_t throttled_queue = ah_throttle_queue_new();
ah_throttle_async(throttled_queue, ^{
// this worker block does some queued work here...
});
您可以使用 ah_throttle_queue
改变队列的节流时间,如下所示
ah_throttle_queue(throttled_queue, 1.5);
注意:任何不是由 AHDispatch 创建的队列(包括 iOS 默认提供的任何队列,如主队列或全局队列),都不会与 AHDispatch 的节流功能兼容。引入这个限制是为了确保只为串行队列使用 AHDispatch。
AHDispatch 是为支持 ARC 的应用程序编写的。默认情况下,您的构建目标需要遵守以下之一
如果您不使用 ARC,仍然可以通过在目标的 构建阶段 选项卡的 编译源 部分中指定 -fobjc-arc
编译器标志来使用 AHDispatch。
AHDispatch.h
中可用的各种调用的摘要。
ah_throttle_queue_new()
ah_throttle_queue_create()
ah_throttle_queue()
所有创建的队列都是序列化的。使用 ah_throttle_queue()
修改队列的节流时间可能会影响已提交到队列中的块,具体取决于队列的节流可变性类型。有关队列可变性的更多信息,请参阅节流可变性。
ah_throttle_queue_new()
创建一个具有以下默认设置的队列:
AH_THROTTLE_TIME_DEFAULT
)。AH_THROTTLE_MUTABILITY_ALL
的 ah_throttle_mutability_t
。AH_THROTTLE_MONITOR_CONCURRENT
的 ah_throttle_monitor_t
。ah_throttle_async
ah_throttle_after_async
ah_throttle_sync
ah_throttle_after_sync
除了标准块提交调用外,即使用接收队列的当前节流时间进行调用的 ah_throttle_async()
和 ah_throttle_sync()
,还可以提交一个指定在执行完该块后应用的单独节流时间的块。这可以通过上述 ah_throttle_after()
变体调用来实现。
当我们谈论节流队列的可变性时,这通常是指节流时间在队列创建和使用后有改变的能力。队列并非以可变数组(NSMutableArray)的方式可变,即对象可以随意添加和删除可变数组中的方式。有时将节流时间视为可变可能更有帮助,因为派送到队列的工作块当然不可变。
在更详细地了解节流可变性之前,我们先简要介绍节流监视器,以便更好地理解节流可变性发生的环境。
节流监视器,由类型 ah_throttle_monitor_t
表示,是一种控制时钟测量和应用的设备。这种时间测量可以并发发生,在执行工作块期间,或者串行,在工作块执行完成后。
串行监视器在工作块执行完成后开始工作。它负责在工作块之间执行和监控节流时间。如果一个队列的节流时间为 0.5 秒,并且有串行监视器,那么每向队列派发一个工作块之间,队列将被节流 0.5 秒。所以如您所见,节流时间监控和执行是与您向节流队列派发的块串行发生的。它们大致在块之间创建了一个时间缓冲。
可以在使用 ah_throttle_queue_create()
函数调用创建队列时指定 AH_THROTTLE_MONITOR_SERIAL
类型的 ah_throttle_monitor_t
常量来将串行监视器应用于队列。
虽然串行监视器很容易理解,但它们并不是监控和应用节流的最佳方法。
在发送到第三方API服务的HTTP请求的上下文中,并发监视器很容易理解。API服务不关心响应返回到客户端需要多长时间,也不关心您的worker阻塞执行需要多长时间。服务只关心您在发送到它的请求之间留下一定的时间。而串行节流监视器测量并应用相对于工作块执行结束的节流时间,相比之下,并发监视器则是测量并应用相对于工作块执行开始的节流时间。
如果最初的worker块在一个0.5秒节流时间的队列中执行需要1.2秒,因为工作块执行完成后已经超出了节流时间(0.7秒),那么下一个worker块将在初始工作块完成后立即执行。所以如您所见,节流时间正在与您派发给节流队列的块进行并发监控。
可以通过调用ah_throttle_queue_new()
或创建队列时指定ah_throttle_monitor_t
类型常量AH_THROTTLE_MONITOR_CONCURRENT
来隐式地应用并发节流监视器到队列中。
节流可变类型控制着队列在节流时间变化方面的行为。如果您从未对现有的队列调用ah_throttle_queue()
,您无需关心节流时间的可变性问题。
如果您更改了现有节流队列的节流时间,了解这一更改对已提交到队列且仍在等待执行的任务块的影响是很重要的。还必须认识节流时间变化对使用ah_throttle_after()
变体调用发出的块的影响,其中指定了一个与队列默认节流时间不同的显式节流时间。
调用ah_throttle_queue_new()
创建的所有队列,都将以AH_THROTTLE_MUTABILITY_ALL
类型的ah_throttle_mutability_t
创建。此类型确保调用ah_throttle_queue()
后,任何已排队等待执行的节流块都将应用此新的节流时间,即使是使用任何ah_throttle_after()
变体调用提交的块。所以所有节流块都是可变的。这是默认设置。在调用更改节流时间的ah_throttle_queue()
之后提交到队列的块将使用隐式节流时间函数调用(ah_throttle_async()
和ah_throttle_sync()
)时分配给它们的新节流时间。当然,在更改默认节流时间后,不管队列的可变性类型如何,这都是正常行为。可变性类型仅影响已经排队的块。
如果您使用AH_THROTTLE_MUTABILITY_DEFAULT
的可变性类型创建节流队列,任何更改带有人群队列的节流时间的调用都只会影响使用假设默认节流时间值时添加的队列中的块。节流时间变化不会影响使用ah_throttle_after()
变体调用发出的块,只会影响使用假设默认节流时间的调用发出的块。
如果您希望防止节流时间更改影响已排队等待执行的块,只需创建一个具有AH_THROTTLE_MUTABILITY_NONE
的ah_throttle_mutability_t
类型的队列。
请注意:节流可变性与已排队等待执行的块相关。无论队列的可变性类型如何,您仍然可以在调用ah_throttle_queue()
后更改并发送到队列的块的标准节流时间。
要使追踪信息输出到控制台,请将密钥 AH_DISPATCH_DEBUG
添加到 目标 的 预处理器宏 列表。在 XCode 5 中,可以在 构建设置 选项卡下的 'Apple LLVM 5.0 - 预处理' 下找到。
AHDispatch 托管仅适用于使用 AHDispatch 的 ah_throttle_queue_create()
和 ah_throttle_queue_new()
函数调用创建的队列。这对于确保与 API 一起使用的队列本质上是串行的来说是必要的。此外,AHDispatch 无法与任何 iOS 附带的标准队列一起工作。这包括主队列和所有全局队列。
尽管在接口中,所有 seconds
参数值都定义为 double
类型,但您可以安全地传递声明为 NSTimeInterval
类型的值。
AHDispatch 由 Ray Scott 维护 (@rayascott)。
AHDispatch 受 MIT 许可证的保护。有关更多信息,请参阅附带的 LICENSE 文件。