(实验)Swift GCD并发

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

异步调用

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

输出

主线程调用<NSThread: 0x1012033b0>{number = 1, name = main}
子线程调用<NSThread: 0x100f4dda0>{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开发中不用添加

输出

主线程调用<NSThread: 0x100f035c0>{number = 1, name = main}
子线程调用<NSThread: 0x101838e00>{number = 2, name = (null)}!
主线程更新UI<NSThread: 0x100f035c0>{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 <NSThread: 0x100f8b380>{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 <NSThread: 0x102103cc0>{number = 4, name = (null)}
loading 1.jpg in <NSThread: 0x100f257f0>{number = 2, name = (null)}
loading 3.jpg in <NSThread: 0x10203c9c0>{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 <NSThread: 0x100f06040>{number = 2, name = (null)}
loading 1.jpg in <NSThread: 0x10191e610>{number = 4, name = (null)}
loading 2.jpg in <NSThread: 0x101a13c60>{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 <NSThread: 0x100f68010>{number = 4, name = (null)}
loading 2.jpg in <NSThread: 0x101a00b00>{number = 3, name = (null)}
loading 1.jpg in <NSThread: 0x100f67f00>{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 <NSThread: 0x102a64e90>{number = 4, name = (null)}
loading 3.jpg in <NSThread: 0x102a64610>{number = 2, name = (null)}
loading 2.jpg in <NSThread: 0x102907eb0>{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 <NSThread: 0x1021219f0>{number = 3, name = (null)}
loading 3.jpg in <NSThread: 0x1021219b0>{number = 2, name = (null)}
loading 1.jpg in <NSThread: 0x100f43850>{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 <NSThread: 0x1018396c0>{number = 2, name = (null)}
loading 1.jpg in <NSThread: 0x100f58390>{number = 3, name = (null)}
2.jpg load success....
1.jpg load success....
loading 3.jpg in <NSThread: 0x1018396c0>{number = 2, name = (null)}
loading 4.jpg in <NSThread: 0x100f58390>{number = 3, name = (null)}
4.jpg load success....
3.jpg load success....
loading 5.jpg in <NSThread: 0x1018396c0>{number = 2, name = (null)}
loading 6.jpg in <NSThread: 0x100f58390>{number = 3, name = (null)}
---------------
5.jpg load success....
6.jpg load success....
loading all success!!!

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容

  • 从哪说起呢? 单纯讲多线程编程真的不知道从哪下嘴。。 不如我直接引用一个最简单的问题,以这个作为切入点好了 在ma...
    Mr_Baymax阅读 2,740评论 1 17
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,864评论 25 707
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,135评论 30 470
  • 火车“咣当咣当”行走了两天一夜,终于稳稳地停了下来。 刚出车站,便接到小虎打来的电话。我吃力地用头夹着电话,一边对...
    兴尽语阅读 264评论 0 7
  • 今天维修一辆日产换离合器,都干完以后发现离合一脚没有了离合,一想还要排气可是没有排过离合器的气,后来在百度上查了一...
    ATurbo阅读 56评论 0 0