我正在异步从数据库中获取数据。有什么办法可以将并发请求限制到一个数字,但仍然执行其余的?我可以使用GCD限制并发请求吗?
我看到使用的NSOperation和NSOperationQueue a post但是这对我来说太复杂了。 有没有其他方法可以做到这一点? GCD可以实现吗?
我正在异步从数据库中获取数据。有什么办法可以将并发请求限制到一个数字,但仍然执行其余的?我可以使用GCD限制并发请求吗?
我看到使用的NSOperation和NSOperationQueue a post但是这对我来说太复杂了。 有没有其他方法可以做到这一点? GCD可以实现吗?
事情是这样的:
...
//only make one of these obviously :) remaking it each time you dispatch_async wouldn't limit anything
dispatch_semaphore_t concurrencyLimitingSemaphore = dispatch_semaphore_create(limit);
...
//do this part once per task, for example in a loop
dispatch_semaphore_wait(concurrencyLimitingSemaphore, DISPATCH_TIME_FOREVER);
dispatch_async(someConcurrentQueue, ^{
/* work goes here */
dispatch_semaphore_signal(concurrencyLimitingSemaphore);
}
欲了解更多详情,请参阅苹果[并发编程指南(https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008091 ),特别是部分[使用调度信号量来调节有限资源的使用方法](https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/ DOC/UID/TP40008091-CH102-SW24)。 –
会不会把'dispatch_semaphore_wait()'调用之前(和外)'dispatch_async()'更好/更高效? – werediver
是的,那么我们需要把这个循环包装在'dispatch_async()'中。这样,我们将在当前运行的顶部_just one_任务,而不是在同一时间所有N. – werediver
最简单的办法是设置N个串行队列
struct dataCalls {
let n:Int
func fetchIt(){
print ("Done",n)
}
init(n:Int){
self.n=n
}
}
var dataCallsArray: [dataCalls]=[]
var qArray:[dispatch_queue_t] = []
let n = 5
for i in 1...50 {
dataCallsArray.append(dataCalls(n:i))
}
for _ in 1...n {
qArray.append(dispatch_queue_create(nil, nil))
}
var i = 0
for data in dataCallsArray {
dispatch_async(qArray[i%n], {() -> Void in data.fetchIt()})
i++
}
注意,如果某些队列比其他队列落后,这将不会在队列之间进行负载平衡。 – Ethan
我建议这个解决方案的同步任务有限的并发执行:
func dispatch_async_batch(tasks: [() ->()], limit: Int, completion: (() ->())?) {
if tasks.count > 0 || completion != nil {
let q = dispatch_queue_create("dispatch_async_batch", DISPATCH_QUEUE_CONCURRENT);
let sema = dispatch_semaphore_create(limit);
dispatch_async(q, {
for task in tasks {
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)
dispatch_async(q, {
task()
dispatch_semaphore_signal(sema)
})
}
if let completion = completion {
dispatch_barrier_async(q, completion)
}
})
}
}
这种方法有小的开销:只Ø将额外的任务放在队列中(即一个额外的线程)撇开目前正在执行的。当你有大量的任务时特别好。
这gist是准备使用的演示,只是把代码放到一个游乐场。
我要说的是使用'NSOperation'和'NSOperationQueue'是不是直接使用GCD容易。 'NSOperationQueue'有一个非常方便的'maxConcurrentOperationsCount'属性。有了GCD,你需要实现你自己的某种计数器。你可以例如使用'dispatch_semaphore'函数家族... – Guillaume
@Guillaume你有我能看到的示例代码吗?我读过一篇教程和课程参考资料,但仍然不太明白。 – user1491987