(实验)Swift GCD并发

本实验使用的是Command Line Tool程序,并非IOS APPlication

异步调用

DispatchQueue.global().async {
    print("子线程调用" + Thread.current.description + "!")
}
print("主线程调用" + Thread.current.description)

输出

主线程调用{number = 1, name = main}
子线程调用{number = 2, name = (null)}!

异步调用获取数据回到主线程更新UI

DispatchQueue.global().async {

    print("子线程调用" + Thread.current.description + "!") //这里同步调用了
    
    DispatchQueue.main.async {
        print("主线程更新UI" + Thread.current.description)
    }
}
print("主线程调用" + Thread.current.description)
RunLoop.current.run() 

由于程序使用Command Line Tool程序 主线程没有RunLoop 所以加上 RunLoop.current.run()
在IOS开发中不用添加

输出

主线程调用{number = 1, name = main}
子线程调用{number = 2, name = (null)}!
主线程更新UI{number = 1, name = main}

可见异步开启了新的线程

异步请求网络数据返回后更新本地

上面的例子是在异步中同步调用数据,一般我们网络数据请求接口封装的都是异步,我们以文件下载为例 (默认使用全局队列)

class LoadHelper {

//��模拟异步下载文件
static func loadFile(_ name:String,_ queue:DispatchQueue = DispatchQueue.global() , _ complete:@escaping ()->Void)
{
    queue.async {
        print("loading " + name + " in " + Thread.current.description)
        let time = arc4random()%3 + 1
        sleep(time)
        complete()
    }
}

}

异步下载一个文件

在main.swift中

LoadHelper.loadFile("1.jpg") {
    print("1.jpg" + " load success....")
}

RunLoop.current.run()

输出

loading 1.jpg in {number = 2, name = (null)}
1.jpg load success....

异步下载多个文件

let array = ["1.jpg", "2.jpg", "3.jpg"]

array.forEach { (name:String) in
    LoadHelper.loadFile(name) {
        print(name + " load success....")
    }
}
RunLoop.current.run()

输出

loading 2.jpg in {number = 4, name = (null)}
loading 1.jpg in {number = 2, name = (null)}
loading 3.jpg in {number = 3, name = (null)}
2.jpg load success....
1.jpg load success....
3.jpg load success....

这个实验的输出前三行或后三行顺序有时会不一样
从输出中可以看除这个实验中,每次下载都开启了一个线程,三个下载任务并发执行的,各个之间没有联系,并且我们不知道什么时候全部下载完毕


多文件下载案例应用

比如现在有这么一个需求,并发下载多个文件,下载完后打印全部下载成功

方法一 (设置下载标记,每个任务下载完后检查标记)

let array = ["1.jpg", "2.jpg", "3.jpg"]
let lock = NSLock()

var completeNum = 0

array.forEach { (name:String) in
    LoadHelper.loadFile(name) {
        print(name + " load success....")
        
        lock.lock()
        completeNum = completeNum + 1
        if completeNum == array.count
        {
            print("loading all success!!!")
            print("Splice all Image!!!")
        }
        lock.unlock()
    }
}
RunLoop.current.run()

输出

loading 3.jpg in {number = 2, name = (null)}
loading 1.jpg in {number = 4, name = (null)}
loading 2.jpg in {number = 3, name = (null)}
1.jpg load success....
2.jpg load success....
3.jpg load success....
loading all success!!!

这种方法比较Low,一般不会这么做

方法二 (栅栏)

let array = ["1.jpg", "2.jpg", "3.jpg"]

let queue = DispatchQueue(label: "anson.gcd.com", attributes: .concurrent)

array.forEach { (name:String) in
    LoadHelper.loadFile(name, queue) {
        print(name + " load success....")
    }
}

let wirte = DispatchWorkItem(flags: .barrier) {
    print("loading all success!!!")
}
queue.async(execute: wirte)
print("---------------")
RunLoop.current.run()

输出

---------------
loading 3.jpg in {number = 4, name = (null)}
loading 2.jpg in {number = 3, name = (null)}
loading 1.jpg in {number = 2, name = (null)}
2.jpg load success....
3.jpg load success....
1.jpg load success....
loading all success!!!

这种方式比较容易理解 而且是非租塞的形式 一般可以使用这种方式获得多异步任务的整体结果回调

方法三 (group)

let array = ["1.jpg", "2.jpg", "3.jpg"]
let queue = DispatchQueue(label: "anson.gcd.com", attributes: .concurrent)
let group = DispatchGroup()

array.forEach { (name:String) in
    group.enter()
    LoadHelper.loadFile(name, queue) {
        print(name + " load success....")
        group.leave()
    }
    
}

group.notify(queue: queue) {
    print("loading all success!!!")
}

print("---------------")
RunLoop.current.run()

输出

---------------
loading 1.jpg in {number = 4, name = (null)}
loading 3.jpg in {number = 2, name = (null)}
loading 2.jpg in {number = 3, name = (null)}
2.jpg load success....
1.jpg load success....
3.jpg load success....
loading all success!!!

这种也是比较常用的

方法四 (GCD 信号量)

let array = ["1.jpg", "2.jpg", "3.jpg"]
let queue = DispatchQueue(label: "anson.gcd.com", attributes: .concurrent)
let semaphoreSignal = DispatchSemaphore(value:0)

array.forEach { (name:String) in
    LoadHelper.loadFile(name, queue) {
        print(name + " load success....")
        semaphoreSignal.signal()
    }
}

array.forEach { (name:String) in
    semaphoreSignal.wait()
}

print("loading all success!!!")
print("---------------")
RunLoop.current.run()

输出

loading 2.jpg in {number = 3, name = (null)}
loading 3.jpg in {number = 2, name = (null)}
loading 1.jpg in {number = 4, name = (null)}
2.jpg load success....
3.jpg load success....
1.jpg load success....
loading all success!!!
---------------

虽然可以实现,但是最后是阻塞的,前面的异步任务没执行完,后面就走不过去

多任务并发控制最大线程数

由于并发任务每一个任务会创建对应的线程,所以有时候我们需要控制任务个数
我们可以在上面方法二到基础上加上信号量控制

let array = ["1.jpg", "2.jpg", "3.jpg", "4.jpg", "5.jpg", "6.jpg"]

let queue = DispatchQueue(label: "anson.gcd.com", attributes: .concurrent)
let semaphoreSignal = DispatchSemaphore(value:2)
array.forEach { (name:String) in
    semaphoreSignal.wait()
    LoadHelper.loadFile(name, queue) {
        print(name + " load success....")
        semaphoreSignal.signal()
    }
}

let wirte = DispatchWorkItem(flags: .barrier) {
    print("loading all success!!!")
}
queue.async(execute: wirte)
print("---------------")
RunLoop.current.run()

输出

loading 2.jpg in {number = 2, name = (null)}
loading 1.jpg in {number = 3, name = (null)}
2.jpg load success....
1.jpg load success....
loading 3.jpg in {number = 2, name = (null)}
loading 4.jpg in {number = 3, name = (null)}
4.jpg load success....
3.jpg load success....
loading 5.jpg in {number = 2, name = (null)}
loading 6.jpg in {number = 3, name = (null)}
---------------
5.jpg load success....
6.jpg load success....
loading all success!!!

当然这也是阻塞的, 不过我们在项目开发中可以把它封装起来,最大并发数由外部传入

你可能感兴趣的:((实验)Swift GCD并发)