本实验使用的是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!!!
当然这也是阻塞的, 不过我们在项目开发中可以把它封装起来,最大并发数由外部传入