美文网首页
多线程之2-DIspatchGroup

多线程之2-DIspatchGroup

作者: 栋柠柒 | 来源:发表于2021-11-22 22:52 被阅读0次

    DispatchGroup用来管理一组任务的执行,然后监听任务都完成的事件。比如,多个网络请求同时发出去,等网络请求都完成后reload UI。

    func dispatchGroupNotify() {
            func simulateNetWork(label: String, cost: UInt32, complete: @escaping ()->Void) {
                print("开始执行  \(label), at \(Date())")
                DispatchQueue.global().async {
                    sleep(cost)
                    print("完成网络请求  \(label), at \(Date())")
                    DispatchQueue.main.async {
                        print("完成UI更新  \(label), at \(Date())")
                        complete()
                    }
                }
            }
            let dispatchGroup = DispatchGroup()
            dispatchGroup.enter()
            simulateNetWork(label: "task1", cost: 2) {
                dispatchGroup.leave()
            }
            dispatchGroup.enter()
            simulateNetWork(label: "task2", cost: 4) {
                dispatchGroup.leave()
            }
            dispatchGroup.notify(queue: DispatchQueue.main, work: DispatchWorkItem(block: {
                print("task1 and task2 finished")
            }))
        }
    
    开始执行  task1, at 2021-11-22 14:21:15 +0000
    开始执行  task2, at 2021-11-22 14:21:15 +0000
    完成网络请求  task1, at 2021-11-22 14:21:17 +0000
    完成UI更新  task1, at 2021-11-22 14:21:17 +0000
    完成网络请求  task2, at 2021-11-22 14:21:19 +0000
    完成UI更新  task2, at 2021-11-22 14:21:19 +0000
    task1 and task2 finished
    
    • wait

    DispatchGroup支持阻塞当前线程,等待执行结果
    如果在提交完第二个任务后等待三秒

    let dispatchGroup = DispatchGroup()
            dispatchGroup.enter()
            simulateNetWork(label: "task1", cost: 2) {
                dispatchGroup.leave()
            }
            dispatchGroup.enter()
            simulateNetWork(label: "task2", cost: 4) {
                dispatchGroup.leave()
            }
    // 在这个地方等待三秒
            print("开始等待 \(Date())")
            dispatchGroup.wait(timeout: .now() + 3)
            print("结束等待 \(Date())")
            dispatchGroup.notify(queue: DispatchQueue.main, work: DispatchWorkItem(block: {
                print("task1 and task2 finished")
            }))
    
    开始执行  task1, at 2021-11-22 14:23:11 +0000
    开始执行  task2, at 2021-11-22 14:23:11 +0000
    开始等待 2021-11-22 14:23:11 +0000
    完成网络请求  task1, at 2021-11-22 14:23:13 +0000
    结束等待 2021-11-22 14:23:14 +0000
    完成UI更新  task1, at 2021-11-22 14:23:14 +0000
    完成网络请求  task2, at 2021-11-22 14:23:15 +0000
    完成UI更新  task2, at 2021-11-22 14:23:15 +0000
    task1 and task2 finished
    
    • Semaphore

    DispatchSemaphore provides an efficient implementation of a traditional counting semaphore, which can be used to control access to a resource across multiple execution contexts.
    DispatchSemaphore是传统计数信号量的封装,用来控制资源被多任务访问的情况。
    从 Apple的接口文档可以看出,
    信号量:就是一种可用来控制访问资源的数量的标识,设定了一个信号量,在线程访问之前,加上信号量的处理,则可告知系统按照我们指定的信号量数量来执行多个线程。
    信号量主要有3个函数,分别是:

    //创建信号量,参数:信号量的初值,如果小于0则会返回NULL

    init(信号量值)

    //等待降低信号量 wait()

    //提高信号量signal()

    注意,正常的使用顺序是先降低然后再提高,这两个函数通常成对使用。 (具体可参考下面的代码示例)

    /**
         * @function dispatch_semaphore_create
         *
         * @abstract
         * Creates new counting semaphore with an initial value.
         *
         * @discussion
         * Passing zero for the value is useful for when two threads need to reconcile
         * the completion of a particular event. Passing a value greater than zero is
         * useful for managing a finite pool of resources, where the pool size is equal
         * to the value.
         *
         * @param value
         * The starting value for the semaphore. Passing a value less than zero will
         * cause NULL to be returned.
         *
         * @result
         * The newly created semaphore, or NULL on failure.
         */
     let semaphore = DispatchSemaphore(value: 2)
    

    这里先将value 设为2,然后开启三个任务

    func semaphoreTest() {
            func portUse(label: String, cost: UInt32, complete: @escaping ()->Void) {
                print("开始使用 \(label)")
                sleep(cost)
                print("结束使用 \(label)")
                complete()
            }
            let semaphore = DispatchSemaphore(value: 2)
            DispatchQueue.global().async {
                semaphore.wait()
                portUse(label: "task1", cost: 2) {
                    semaphore.signal()
                }
            }
            DispatchQueue.global().async {
                semaphore.wait()
                portUse(label: "task2", cost: 4) {
                    semaphore.signal()
                }
            }
            DispatchQueue.global().async {
                semaphore.wait()
                portUse(label: "task3", cost: 1) {
                    semaphore.signal()
                }
            }
        }
    
    开始使用 task2
    开始使用 task1
    结束使用 task1
    开始使用 task3
    结束使用 task3
    结束使用 task2
    

    可以看出,task1 和 task2 都开始执行,当task1 执行完毕后,task3 才会开始执行,说明value 设为2 的时候,只能够同时执行2个任务,task 1执行完毕后,会signal 一个信号量,所以task 3 就可以执行了.
    然后将value 设为1 ,看下输出

    开始使用 task1
    结束使用 task1
    开始使用 task2
    结束使用 task2
    开始使用 task3
    结束使用 task3
    

    一次只能执行一个任务
    再将 value改为3 看看

    开始使用 task2
    开始使用 task1
    开始使用 task3
    结束使用 task3
    结束使用 task1
    结束使用 task2
    

    可以看到三个任务同时开始,没有互相限制。

    相关文章

      网友评论

          本文标题:多线程之2-DIspatchGroup

          本文链接:https://www.haomeiwen.com/subject/ylhitrtx.html