Can I limit concurrent requests using GCD?

后端 未结 3 1560
眼角桃花
眼角桃花 2020-12-18 05:06

I\'m acquiring data from a database asynchronously. Is there any way I can limit the concurrent requests to a number, but still execute the rest?

I saw a post using

相关标签:
3条回答
  • 2020-12-18 05:13

    The easy way is to set up n serial queues

    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++
    }
    
    0 讨论(0)
  • 2020-12-18 05:25

    I suggest this solution for limited concurrent execution of synchronous tasks:

    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)
                }
            })
        }
    }
    

    This approach has small overhead: only one extra task is put on the queue (i.e. one extra thread) aside the currently executing ones. It's especially good when you have big overall amount of tasks.

    This gist is a ready to use demo, just put the code into a playground.

    0 讨论(0)
  • 2020-12-18 05:27

    Something like this:

    ...
    //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);
    }
    
    0 讨论(0)
提交回复
热议问题