编程语言
首页 > 编程语言> > Swift5.x 多线程编程

Swift5.x 多线程编程

作者:互联网

//
//  ViewController16.swift
//  swiftT
//
//  Created by wjwdive on 2020/6/1.
//  Copyright © 2020 wjwdive. All rights reserved.
//

import UIKit

class ViewController16: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        //1 Thread多线程打印1到10
        for i in 0..<10 {
            Thread.detachNewThread{
                 print(i)//打印是无序的,
            }
        }
        
        //2
        let obj = ObjectThread()
        obj.threadTest()//
        
        //Operation queue  创建队列并添加操作
        let operation = ObjectForThread()
        operation.threadTest()
        
        //completionBlock
        let operationCallBack = ObjectCompletionBlock()
        operationCallBack.threadTest()
        
        //qos 服务质量
        //DispatchQoS.default
        //DispatchQoS.background
        //DispatchQoS.userInitiated
        //DispatchQoS.userInteractive
        //DispatchQoS.unspecified

        //
        
        // 创建一个队列
        let queue = DispatchQueue(label: "myQueue", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency:
            DispatchQueue.AutoreleaseFrequency.inherit, target: nil)
        //同步执行一个任务
        queue.sync {
            print("in queu sync")
        }
        
        print("after invoke queue method!")
        //延迟执行
        queue.asyncAfter(deadline: .now() + 2) {
            print("asyncAfter")
        }
        //系统时钟 关机之后系统时钟会暂停
        //DispatchTime
        //墙上挂的时钟   ,不关注系统时间,关机计算时间
        //DispatchWallTime
        
        
        let group = DispatchGroup()
        group.enter()
        queue.async {
            sleep(1)
            print("模拟接口1请求完成")
            group.leave()
        }
        
        group.enter()
        queue.async {
            sleep(1)
            print("模拟接口2请求完成")
            group.leave()
        }
        
        print("group enter() 调用完成")
        group.wait()//阻塞
        print("接口1,接口2调用完成")
        
        let groupn = DispatchGroup()
        groupn.enter()
        print("groupn enter() 调用完成")

        queue.async {
            sleep(1)
            print("模拟接口A请求完成")
            groupn.leave()
        }
        
        groupn.enter()
        queue.async {
            sleep(1)
            print("模拟接口B请求完成")
            groupn.leave()
        }
        
        print("groupn enter() 调用完成")
        groupn.notify(queue: queue) {
            print("接口A,接口B调用完成")
        }
        print("验证不阻塞")
        
        
        //timer
        var seconds = 10
        let timer = DispatchSource.makeTimerSource(flags: [], queue: queue)
        timer.schedule(deadline: .now(), repeating: 1.0)
        timer.setEventHandler {
            seconds -= 1
            if seconds < 0 {
                timer.cancel()
            } else {
                print(seconds)
            }
        }
        timer.resume()
        
        
        //串行队列里先同步调一个任务,任务里再同步调一个任务
        lockSimple()
        
    }

}

// Swift多线程编程
// 思考: 为什么几乎所有的GUI框架都是单线程的?
// 回答: 因为多线程会有线程调度,虽然多线程会加快运算速度,但是带来的线程调度和开销,资源抢占,死锁等问题会更多。

// 多线程编程方式:【3种】
// Thread, Cocoa Operation, GCD(Grand Central Dispatch)

// Thread,在三种多线程技术中是最轻量级的,但需要自己管理自己线程的生命周期和线程同步。线程同步对数据的枷锁会有一定的系统开销。

//
//Thread 创建线程的3种方式
func ThreadCreat1() {
    //1
    Thread.detachNewThread {
        print("detachNewThread creat a therad!")
    }
    
}
//
//func ThreadCreat2() {
//    //2
//    Thread.detachNewThreadSelector(#seletor(funcName): Selector, toTarget: self, with: nil) {
//
//    }
//
//}
//
//func ThreadCreat3() {
//    //3
//    Thread(target: self., selector: #seletor(funcName), object: nil)
//}



//在Playground里需要添加以下声明
//import PlaygroundSupport
//PlaygroundPage.current.needIndefiniteExecution = true
class ObjectThread {
    func threadTest() {
        let thread = Thread(target: self, selector: #selector(threadWorker), object: nil)
        //使用初始化器创建的线程需要手动start
        thread.start()
    }
    
    @objc func threadWorker() {
        print("threadWorker")
    }
}

//面向对象
// Operation + OperationQueue
//取消,依赖,任务优先级,复杂逻辑,保存业务子状态,子类化
//Operation, Block Operation

//Operation四个状态(属性)
//1、 isReady
//2、 isExecuting
//3、 isFinished
//4、 isCancelled

// OPeration 运行方式
// 1、sync 同步 在main方法里
// 2、async 异步,比如网络请求
// start()
// isAsynchromous
// isExecuting
// isFinished

// Operation可以添加依赖
//func addDependency(Operation)
//func removeDependency(Operation)
//var dependencied:[Operation]

//Operation Queue
//1、Operation Queue队列里可以加入很多个Operation, 可以把OperationQueue看作一个线程池,可以往线程池中添加操作(Operation)到队列中
//2、底层使用GCD
//3、maxConcurrentOperationCount 可以设置最大并发数【最多不超过5个】
//4、defaultMaxConcurrentOperationCount 根据当前系统条件动态确定的最大并发数
//5、可以取消所有Operation,但是当前正在执行的不会执行
//6、所有Operation执行完毕后退出销毁

//BlockOperation
class ObjectForThread {
    func threadTest() {
        let operation = MyOperation()
        let queue = OperationQueue()
        queue.addOperation(operation)
    }
}

class MyOperation: Operation {
    override func main() {
        sleep(1)
        print("MyOperation")
    }
}


//completionBlock  带回调的OperationBlock
class ObjectCompletionBlock {
    func threadTest() {
        let operation = MyOperation()
        operation.completionBlock = {()-> Void in
            print("---operation.completionBlock---")}
        let queue = OperationQueue()
        queue.addOperation(operation)
        print("threadTest")
    }
}



//封装一个网络请求

//GCD
// 任务+队列
// 易用,高效,性能
//功能:
//1、创建管理Queue
//2、提交Job
//3、Dispatch Group
//4、管理Dispatch Object
//5、信号量 Semaphore
//6、队列屏障
//7、Dispatch Source
//8、Queue Context 数据
//9、Dispatch I/O Channel
//10、Dispatch Data 对象


// Dispatch.main
// Dispatch.global
// DispatchQueue(label:,qos:,autoreleaseFrequency:,target:) //自己创建
// queue.label
// setTarget(queue: DispatchQueue?)

//GCD-队列
//1、最终的目标队列都是主队列和全局队列
//2、如果把一个并行队列的目标队列设置成一个串行队列,那么并行队列将不再并行
//3、如果多个队列的目标队列都设置为同一个串行队列,那么这多个队列连同b目标队列里的任务都将穿行执行
//4、如果设置目标队列形成了环,结果是不可预期的
//5、如果在一个队列正在执行任务的时候更换目标队列,结果也是不可预期的

//GCD里的基本操作
//1、穿行和并行:描述任务之间是如何运行的,串行任务每次仅仅执行一个,并行任务可以多个同时执行
//2、同步和异步: 描述的是任务的执行过程是如何的。同步:同一个过程会等待

//同步任务
// A
// |
// B
// |
// A

//异步任务
// A
// |\
// A B
// | /
// A

// GCD-sync
// 提交任务到当前队列里,并且直到任务执行完成,当前队列才返回
//func sync(execute: DispatchWorkItem)
// submints a work for execution on the current queue and returns after that block finished executing

//func sync(execute: () -> Void)
// submits a block object for executino and returns after that block finishes executing

//func sync<T>(execute: () -> T) -> T
//submits a work item for execution and returns the results from that item after it finishes executing
//func sync<T>(flags: DispatchWorkItemFlags, execute:() -> T) -> T
//Submits a work item for execution using the specified attributes and returns the results from that item after it finishes executing

//GCD-async
//调度一个任务立即取执行,但是不用等待任务执行完当前队列就会返回

//GCD-asyncAfter
//调度一个任务多久之后执行,但是不用等待任务执行完当前队列就会返回
//DispatchQueue.main.asyncAfter(deadline: .now() + 2.5) {
    //执行的任务
    //print("延迟2.5s执行的任务")
//}


//DispatchGroup
//enter和leave必须成对出现
//DispatchGroup-wait


//DispatchGroup-notify

//DispatchSource
//dispatch source是一个监视某些类型事件的对象。这些事件发生时,它自动将一个task放入一个dispatch queue的执行历程中
//用途
//Mach port send right state changes
//Mach port receive right state changes
//External process state change
//File descriptor ready for read
//File descriptor ready for write
//Filesystem node event.
//PPSIX signal
//custom timer
//custom event

// GCD源码剖析


// 一个死锁的例子
//串行队列,异步执行一个任务,任务里又串行执行一个任务
func lockSimple() {
    let queue = DispatchQueue(label: "serial queue")
    queue.async {
        print("in queue async")
        queue.async {
            print("in queue sync")
        }
    }
}

//并行队列不会死锁了
func noLockSimple() {
    let queueCuncurrent = DispatchQueue(label: "concurrent queue", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)
    queueCuncurrent.async {
        print("in queueCuncurrent async")
        queueCuncurrent.sync {
            print("in queueCuncurrent sync")
        }
    }
}


// 死锁
//资源竞争或彼此通讯 死锁时指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞现象,若无外力作用,它们都将无法推进下去。此时系统处于死锁状态或者系统产生了死锁。
//例子:线程A 在t1时刻占用了X资源(t1开始A锁定了X),线程B在t2时刻占用了Y资源(t2开始B锁的了Y),t3时刻线程A又要尝试占用Y资源(资源Y t2 时刻就已被线程B锁的),t4时刻线程B又要尝试占用资源X,这时候就会发生死锁。AB线程都个字拥有了资源但又需要对方已经在使用的资源,就会发生死锁。(时刻:t1 < t2 < t3 < t4)
// 临界区:
// 就是一段代码不能被并发执行,也就是,两个线程不能同时执行这段代码

// 静态条件
// 两个或多个线程读写某些共享数据,而最后的结果取决于线程运行时的精确时序。
// 例如多个线程读写银行存款余额,

// 优先级反转
// 假如有高A-中B-低C3种优先级的线程,t1时刻低优先级的线程C先获取了一个共享资源S,t2时刻,高优先级的线程A尝试获取资源S,但是线程C还在占用资源S,所以A就被挂起了。这时B就有了最高可运行优先级,B在C运行完之后会立即获取到资源S(A还在挂起状态),B继续占有S运行,期间A会继续间隔尝试获取S,但是得不到S无法运行,期间C若要再次运行,他没有B的优先级高也得不到S.所以优先级排序ABC变成了BAC。也就是优先级反转

// 并发与并行
// 并行:一般发生在CPU多核多线程的情况下,两个线程在两个核上同时执行,而不需要间断
// 并发:需要有一些对线程持续的调度,或者有一些上下文的切换,来看起来像Thread1,Thread2同时执行。但实际上是两个线程相互让渡系统执行事件来达到的一种假象。
//
//iOS中的锁
//1 OSSpinLock
//2 dispatch_semaphore
//3 pthread_mutex
//4 NSLock
//5 NSCondation
//6 pthread_mutex(recursive)
//7 NSRecursiveLock
//8 NSConditionLock
//9 @synchronized swift 中已被移除

//1 OSSpinLock:
// 线程是通过busy-wait-loop的方式来获得锁的,任意时刻只有一个线程能获得锁,其他线程忙等待直到获得锁。
// 普通的锁实现,当一个线程加锁一个资源时,其他的线程再访问资源,就获取不到,就会进入休眠状态,直到活跃线程执行完,等待系统把休眠的线程唤醒,才能给资源加上锁继续执行。但是OSSpinLock任意时刻只有一个线程能获得锁,其他线程忙等待直到获得锁。

//bool lock = false //一开始没有锁上,任何线程都可以申请锁
//do {
//    while(test_and_set(&lock));//test_and_set是一个原子操作
//        Critical section;//临界区
//    lock = fasle // 相当于释放锁,这样别的线程可以进入临界区
//        Reminder section //不需要锁保护代码
//}

//OSSpinLock适用范围
//1、临界区尽量简短,控制在100行代码以内,不要有显式或隐式的系统调用,调用的函数也尽量简短。因为执行临界区代码非常长的话,所有的等待进入临界区的线程访问临界区的时候都会忙等待,造成资源浪费或卡顿。
//2、保证访问锁的线程全部都处于同一优先级。可能会出现优先级反转

//9 @synchronized swift 中已被移除,不过可以自己实现该功能
func synchorized(_ obj: AnyObject, closure: () -> () ) {
    objc_sync_enter(obj)
    closure()
    objc_sync_exit(obj)
}
//注意点:
//1 只有传同样的synchronized,才能起到加锁作用
//2 如果传 nil ,无法起到加锁的作用
//3 可以重用
//4 synchorized不会持有传给他的对象

//objc_sync_enter的实现
//int objc_sync_enter(id obj) {
//    int result = OBJC_SYNC_SUCCESS;
//    if(obj) {
//        SyncData *data = id2data(obj, ACQUIRE);
//        assert(data);
//        data->mutex.lock();
//    }else {
//        //@synchorized(nil) does nothing
//        if(DebugNilSync) {
//            _objc_inform("NIL SYNC DEBUG: @synchorized(nil);set a breadpoint on 0bjc_sync_nil to debug")
//        }
//        objc_sync_nil();
//
//    }
//    return result;
//}

// end synchorizing on 'obj'.
// Returns OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR
//int objc_sync_exit(id obj){
//    int reuslt = OBJC_SYNC_SUCCESS;
//    if(obj) {
//        SyncData *data = id2data(obj, RELEASE);
//        if(!data) {
//            result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
//        }else {
//            bool okay = data->mutex.tryUnlock();
//            if(!okay) {
//                result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
//            }
//        }
//    } else {
//        // @synchorized(nil) does nothing
//    }
//    return result
//}

// SyncData是什么?
//1 SyncData是可以重用的,(threadCount == 0)
//2 存在全局的map里

//SyncData 定义
//typedef struct alignas(ChaheLineSize) SyncData {
//    struct SyncData* nextData;
//    DisguisedPtr<ojc_object> object;
//    int32_t threadCount;
//    recursive_mutext_t mutex;
//} SyncData;

//如果是对 ObjcA, ObjcB, ObjcC 三个对象进行synchorized操作,其中先对ObjcA操作两次。

//多线程的应用场景
//1 一个也没有三个网络请求,需要再三个网络请求返回的时候刷新界面
//2 需要一个线程安全的Array的读写
//3 编写一个多线程下载器,可执行多个下载任务,每个任务可以保存当下下载的字节数,总字节数,可以设置回调得到当前下载进度
//4 需要再主线程等待一个异步任务返回,才能继续执行下面的逻辑,但是又不希望堵塞用户事件。


标签:执行,队列,编程,sync,queue,任务,线程,Swift5,多线程
来源: https://www.cnblogs.com/wjw-blog/p/13038553.html