GCD系列 一 使用队列(2)

GCD 队列使用

文档

先看官方文档, DispatchQueue 是一个class对象,继承自 DispatchObject;
DispatchObject 实现了 OS_object 中的方法, 猜测 OS_object 可能是一个协议,文档中没有查找到
先看 DispatchObject:

func activate() 
    Activates the dispatch object.
func resume()
    Resumes the invocation of block objects on a dispatch object.
func suspend()
    Suspends the invocation of block objects on a dispatch object.
func setTarget(queue: DispatchQueue?)
    Specifies the dispatch queue on which to perform work associated with the current object.
enum DispatchPredicate
    Logical conditions to evaluate within a given execution context.
func dispatchPrecondition(condition() -> DispatchPredicate)
    Checks a dispatch condition necessary for further execution.

也就是说 DispatchQueue 作为一个队列,本身也实现了上面的方法,此外,自身也实现了下面的方法ß

class var main: DispatchQueue
    The dispatch queue associated with the main thread of the current process.
class func global(qos: DispatchQoS.QoSClass) -> DispatchQueue
    Returns the global system queue with the specified quality-of-service class.
init(label: String, qos: DispatchQoS, attributes: DispatchQueue.Attributes, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency, target: DispatchQueue?)
    Creates a new dispatch queue to which you can submit blocks.
enum DispatchQoS.QoSClass
    Quality-of-service classes that specify the priorities for executing tasks.
struct DispatchQueue.Attributes
    Attributes that define the behavior of a dispatch queue.
enum DispatchQueue.AutoreleaseFrequency
    Constants indicating the frequency with which a dispatch queue autoreleases objects.
class OS_dispatch_queue_main
    A system-provided dispatch queue that schedules tasks for serial execution on the app's main thread.
class OS_dispatch_queue_global
    A system-provided dispatch queue that schedules tasks for concurrent execution.
class OS_dispatch_queue_serial
    A custom dispatch queue that schedules tasks for serial execution on an arbitrary thread.
class OS_dispatch_queue_concurrent
    A custom dispatch queue that schedules tasks for concurrent execution.

根据文档介绍:

  • DispatchQueue 是一个先进先出的队列,用户提交任务到队列中, 队列会将任务调度给线程池中的线程执行
  • 执行用户提交的任务可以同步也可以异步, 可以串行也可以异步执行,在mainQueue的任务只能串行

文档提醒:
使用队列的时候,需要避免过多的创建线程:

  • 避免在并发队列中执行任务时, block任务的执行,因为调度系统在此时的情景下,会继续创建线程
  • 避免创建自己的队列,因为创建自己的队列会消耗线程资源,你应该通过设置targetQueue的方式指向globalQueue,避免过多创建线程

实践

创建不同的队列

  • 主队列: DispatchQueue.main
  • 全局队列:DispatchQueue.global()
  • 自建串行队列: DispatchQueue.init(label: “test.serial.queue”)
  • 自建并发队列:DispatchQueue.init(label: “test.serial.queue”, attributes: .concurrent)
import Foundation

func createQueue() {
    /// 主队列
    let mainQueue = DispatchQueue.main
    print(mainQueue) // <OS_dispatch_queue_main: com.apple.main-thread>

    /*
    class func global(qos: DispatchQoS.QoSClass = .default) -> DispatchQueue
    默认是default优先级, globalQueue是并发队列
    */
    let globalQueue = DispatchQueue.global()
    print(globalQueue) // <OS_dispatch_queue_global: com.apple.root.default-qos>

    /// 创建自定义队列, 串行
    let customSerialQueue = DispatchQueue.init(label: "test.serial.queue")
    print(customSerialQueue)
    /*
     创建并发队列,此时未指定优先级, 优先级是
     可以指定是否是并发,不指定默认串行,此外可以指定新建的队列是未激活状态
     static let concurrent: 
        DispatchQueue.Attributes The queue schedules tasks concurrently.
     static let initiallyInactive: DispatchQueue.Attributes
        The newly created queue is inactive.
    */
    let customCurrentQueue = DispatchQueue.init(label: "test.serial.queue", attributes: .concurrent)
    print(customCurrentQueue)
}


createQueue()

使用主队列

主队列主要是任务需要放在主线程执行的时候使用
可以将异步任务放在主线程并发执行
在主线程中同步sync执行主队列的任务会导致死锁

import Foundation
/*
result:
useMainQueue start
useMainQueue end
useMainQueue task excuting
*/
func useMainQueue1() {
    /// 主队列
    print("useMainQueue start")
    let mainQueue = DispatchQueue.main
    mainQueue.async {
        print("useMainQueue task excuting")
    }
    print("useMainQueue end")
}
// useMainQueue1()

/*
result:
useMainQueue start
useMainQueue end
useMainQueue2 start
[2]    54143 illegal hardware instruction  ./task
*/
func useMainQueue2() {
    /// 主队列
    print("useMainQueue2 start")
    let mainQueue = DispatchQueue.main
    mainQueue.sync {
        print("useMainQueue2 task excuting")
    }
    print("useMainQueue2 end")
}
// useMainQueue2()

/*
result:
useMainQueue3 start
useMainQueue3 task excuting
useMainQueue3 end
*/
func useMainQueue3() {
    /// 主队列
    print("useMainQueue3 start")
    let mainQueue = DispatchQueue.main
    mainQueue.sync {
        print("useMainQueue3 task excuting")
    }
    print("useMainQueue3 end")
}
DispatchQueue.global().async {
    useMainQueue3()
}

RunLoop.main.run()

使用全局队列

    @objc func test() {
        print("\n\n")
        
        DispatchQueue.global(qos: .default).async {
            print("default", Thread.current)
        }
        DispatchQueue.global(qos: .background).async {
            print("background", Thread.current)
        }
        DispatchQueue.global(qos: .unspecified).async {
            print("unspecified", Thread.current)
        }
        DispatchQueue.global(qos: .userInitiated).async {
            print("userInitiated", Thread.current)
        }
        DispatchQueue.global(qos: .utility).async {
            print("utility", Thread.current)
        }
        DispatchQueue.global(qos: .userInteractive).async {
            print("userInteractive", Thread.current)
        }
    }


结果

default <NSThread: 0x600003255400>{number = 4, name = (null)}
utility <NSThread: 0x6000032483c0>{number = 7, name = (null)}
unspecified <NSThread: 0x60000323a3c0>{number = 8, name = (null)}
userInteractive <NSThread: 0x60000322f000>{number = 9, name = (null)}
userInitiated <NSThread: 0x6000032416c0>{number = 10, name = (null)}
background <NSThread: 0x6000032483c0>{number = 7, name = (null)}



default <NSThread: 0x6000032416c0>{number = 10, name = (null)}
userInteractive <NSThread: 0x600003252140>{number = 12, name = (null)}
unspecified <NSThread: 0x60000322ec40>{number = 11, name = (null)}
userInitiated <NSThread: 0x6000032416c0>{number = 10, name = (null)}
utility <NSThread: 0x6000032416c0>{number = 10, name = (null)}
background <NSThread: 0x6000032416c0>{number = 10, name = (null)}



default <NSThread: 0x6000032416c0>{number = 10, name = (null)}
unspecified <NSThread: 0x600003232f80>{number = 14, name = (null)}
userInteractive <NSThread: 0x60000327c380>{number = 13, name = (null)}
userInitiated <NSThread: 0x6000032416c0>{number = 10, name = (null)}
utility <NSThread: 0x60000327c380>{number = 13, name = (null)}
background <NSThread: 0x6000032416c0>{number = 10, name = (null)}



default <NSThread: 0x60000327c380>{number = 13, name = (null)}
unspecified <NSThread: 0x600003232f80>{number = 14, name = (null)}
userInteractive <NSThread: 0x600003241ec0>{number = 15, name = (null)}
userInitiated <NSThread: 0x600003227fc0>{number = 16, name = (null)}
utility <NSThread: 0x600003227fc0>{number = 16, name = (null)}
background <NSThread: 0x6000032416c0>{number = 10, name = (null)}



default <NSThread: 0x600003227fc0>{number = 16, name = (null)}
userInteractive <NSThread: 0x600003241ec0>{number = 15, name = (null)}
unspecified <NSThread: 0x600003232f80>{number = 14, name = (null)}
userInitiated <NSThread: 0x60000327c380>{number = 13, name = (null)}
utility <NSThread: 0x6000032416c0>{number = 10, name = (null)}
background <NSThread: 0x6000032416c0>{number = 10, name = (null)}



default <NSThread: 0x6000032416c0>{number = 10, name = (null)}
unspecified <NSThread: 0x60000327c380>{number = 13, name = (null)}
userInteractive <NSThread: 0x600003241ec0>{number = 15, name = (null)}
userInitiated <NSThread: 0x600003227fc0>{number = 16, name = (null)}
utility <NSThread: 0x600003232f80>{number = 14, name = (null)}
background <NSThread: 0x60000327c380>{number = 13, name = (null)}



default <NSThread: 0x600003232f80>{number = 14, name = (null)}
unspecified <NSThread: 0x600003227fc0>{number = 16, name = (null)}
userInteractive <NSThread: 0x600003241ec0>{number = 15, name = (null)}
userInitiated <NSThread: 0x6000032416c0>{number = 10, name = (null)}
utility <NSThread: 0x60000327c380>{number = 13, name = (null)}
background <NSThread: 0x600003241ec0>{number = 15, name = (null)}



default <NSThread: 0x60000327c380>{number = 13, name = (null)}
unspecified <NSThread: 0x6000032416c0>{number = 10, name = (null)}
userInteractive <NSThread: 0x600003227fc0>{number = 16, name = (null)}
userInitiated <NSThread: 0x600003232f80>{number = 14, name = (null)}
utility <NSThread: 0x600003241ec0>{number = 15, name = (null)}
background <NSThread: 0x600003227fc0>{number = 16, name = (null)}

老版本可以指定4个优先级


    @objc func test() {
        print("\n\n")
        /// high > default > low > background
        /// 'global(priority:)' was deprecated in iOS 8.0
        DispatchQueue.global(priority: .low).async {
            print("low", Thread.current)
        }
        
        DispatchQueue.global(priority: .default).async {
            print("default", Thread.current)
        }
        
        DispatchQueue.global(priority: .background).async {
            print("background", Thread.current)
        }
        
        DispatchQueue.global(priority: .high).async {
            print("high", Thread.current)
        }
    }

结果

default <NSThread: 0x600002b511c0>{number = 7, name = (null)}
high <NSThread: 0x600002b33900>{number = 5, name = (null)}
low <NSThread: 0x600002b75d40>{number = 6, name = (null)}
background <NSThread: 0x600002b505c0>{number = 4, name = (null)}



default <NSThread: 0x600002b75d40>{number = 6, name = (null)}
high <NSThread: 0x600002b505c0>{number = 4, name = (null)}
low <NSThread: 0x600002b33900>{number = 5, name = (null)}
background <NSThread: 0x600002b511c0>{number = 7, name = (null)}



default <NSThread: 0x600002b511c0>{number = 7, name = (null)}
high <NSThread: 0x600002b33900>{number = 5, name = (null)}
low <NSThread: 0x600002b33900>{number = 5, name = (null)}
background <NSThread: 0x600002b505c0>{number = 4, name = (null)}



default <NSThread: 0x600002b33900>{number = 5, name = (null)}
high <NSThread: 0x600002b511c0>{number = 7, name = (null)}
low <NSThread: 0x600002b505c0>{number = 4, name = (null)}
background <NSThread: 0x600002b511c0>{number = 7, name = (null)}



default <NSThread: 0x600002b505c0>{number = 4, name = (null)}
high <NSThread: 0x600002b75d40>{number = 6, name = (null)}
low <NSThread: 0x600002b511c0>{number = 7, name = (null)}
background <NSThread: 0x600002b33900>{number = 5, name = (null)}



default <NSThread: 0x600002b511c0>{number = 7, name = (null)}
high <NSThread: 0x600002b75d40>{number = 6, name = (null)}
low <NSThread: 0x600002b33900>{number = 5, name = (null)}
background <NSThread: 0x600002b505c0>{number = 4, name = (null)}



default <NSThread: 0x600002b33900>{number = 5, name = (null)}
high <NSThread: 0x600002b511c0>{number = 7, name = (null)}
low <NSThread: 0x600002b505c0>{number = 4, name = (null)}
background <NSThread: 0x600002b75d40>{number = 6, name = (null)}



default <NSThread: 0x600002b75d40>{number = 6, name = (null)}
high <NSThread: 0x600002b505c0>{number = 4, name = (null)}
low <NSThread: 0x600002b505c0>{number = 4, name = (null)}
background <NSThread: 0x600002b511c0>{number = 7, name = (null)}



default <NSThread: 0x600002b511c0>{number = 7, name = (null)}
high <NSThread: 0x600002b33900>{number = 5, name = (null)}
low <NSThread: 0x600002b505c0>{number = 4, name = (null)}
background <NSThread: 0x600002b75d40>{number = 6, name = (null)}



default <NSThread: 0x600002b75d40>{number = 6, name = (null)}
high <NSThread: 0x600002b505c0>{number = 4, name = (null)}
low <NSThread: 0x600002b33900>{number = 5, name = (null)}
background <NSThread: 0x600002b505c0>{number = 4, name = (null)}



default <NSThread: 0x600002b505c0>{number = 4, name = (null)}
high <NSThread: 0x600002b33900>{number = 5, name = (null)}
low <NSThread: 0x600002b511c0>{number = 7, name = (null)}
background <NSThread: 0x600002b33900>{number = 5, name = (null)}



default <NSThread: 0x600002b33900>{number = 5, name = (null)}
high <NSThread: 0x600002b511c0>{number = 7, name = (null)}
low <NSThread: 0x600002b511c0>{number = 7, name = (null)}
background <NSThread: 0x600002b505c0>{number = 4, name = (null)}



default <NSThread: 0x600002b505c0>{number = 4, name = (null)}
high <NSThread: 0x600002b511c0>{number = 7, name = (null)}
low <NSThread: 0x600002b33900>{number = 5, name = (null)}
background <NSThread: 0x600002b511c0>{number = 7, name = (null)}



low <NSThread: 0x600002b511c0>{number = 7, name = (null)}
default <NSThread: 0x600002b33900>{number = 5, name = (null)}
high <NSThread: 0x600002b505c0>{number = 4, name = (null)}
background <NSThread: 0x600002b511c0>{number = 7, name = (null)}



default <NSThread: 0x600002b511c0>{number = 7, name = (null)}
high <NSThread: 0x600002b75d40>{number = 6, name = (null)}
low <NSThread: 0x600002b75d40>{number = 6, name = (null)}
background <NSThread: 0x600002b75d40>{number = 6, name = (null)}



default <NSThread: 0x600002b75d40>{number = 6, name = (null)}
low <NSThread: 0x600002b505c0>{number = 4, name = (null)}
high <NSThread: 0x600002b511c0>{number = 7, name = (null)}
background <NSThread: 0x600002b33900>{number = 5, name = (null)}



default <NSThread: 0x600002b33900>{number = 5, name = (null)}
high <NSThread: 0x600002b505c0>{number = 4, name = (null)}
low <NSThread: 0x600002b505c0>{number = 4, name = (null)}
background <NSThread: 0x600002b511c0>{number = 7, name = (null)}



default <NSThread: 0x600002b511c0>{number = 7, name = (null)}
high <NSThread: 0x600002b505c0>{number = 4, name = (null)}
low <NSThread: 0x600002b505c0>{number = 4, name = (null)}
background <NSThread: 0x600002b33900>{number = 5, name = (null)}



default <NSThread: 0x600002b33900>{number = 5, name = (null)}
high <NSThread: 0x600002b511c0>{number = 7, name = (null)}
low <NSThread: 0x600002b505c0>{number = 4, name = (null)}
background <NSThread: 0x600002b75d40>{number = 6, name = (null)}



low <NSThread: 0x600002b75d40>{number = 6, name = (null)}
default <NSThread: 0x600002b505c0>{number = 4, name = (null)}
high <NSThread: 0x600002b511c0>{number = 7, name = (null)}

GCD 可以创建的Thread数量

根据资料, gcd内部限制至多512个线程, 加上其他4个线程,一个516个

Special note here:

The 512 mentioned is the limit of gcd. After the 512 gcd threads are opened, you can still open them with NSThread.

So the chart above

Currently it should be 512, 516 = 512(max) + main thread + js thread + web thread + uikit event thread"


https://stackoverflow.com/questions/7213845/number-of-threads-created-by-gcd

题目分析

  • 下面的题目的输出结果
class ViewController: UIViewController {
    var number: Int = 0
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let button = UIButton()
        button.setTitle("Test", for: .normal)
        button.setTitleColor(.red, for: .normal)
        button.sizeToFit()
        button.addTarget(self, action: #selector(test), for: .touchUpInside)
        view.addSubview(button)
        button.center = view.center
    }
    
    @objc func test() {
        while number < 5 {
            DispatchQueue.global().async {
                self.number += 1
            }
        }
        print(number)
    }
}

理论结果, number >= 5; 实际测试是在14、 15左右

  • 下面的题目的输出结果(上面的test方法替换成下面的方法)
    @objc func test() {
        number = 0
        for _ in 1...1000 {
            DispatchQueue.global().async {
                self.number += 1
            }
        }
        print(number)
    }

理论结果,0 <= number <= 1000 > && ; 实际测试结果

994
996
987
993
977
996
993

  • 下面方法最后输出的顺序是什么样的
 @objc func test() {
        let queue = DispatchQueue.init(label: "test", qos: .default, attributes: .concurrent)
        queue.async {
            print(1)
        }
        queue.async {
            print(2)
        }
        queue.sync {
            print(3)
        }
        print(0)
        queue.async {
            print(4)
        }
        queue.async {
            print(5)
        }
        queue.async {
            print(6)
        }
    }

理论结果, 3在0之前, 0在 456之前; 实际

3
0
1
2
4
6
5

  • 下面的题目输出的结果是什么?
    @objc func test() {
        print("\n\n")
        let queue = DispatchQueue.init(label: "test", qos: .default, attributes: .concurrent)
        print(1)
        queue.async {
            print(2)
            queue.async {
                print(3)
            }
            Thread.sleep(forTimeInterval: 0.5)
            print(4)
        }
        Thread.sleep(forTimeInterval: 0.5)
        print(5)
    }

理论结果:最开始输出1,2在34之前,3和4顺序不确定;5和234之间顺序不确定;
实际测试:如果不延时,是15243,如果延时 12354

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值