//
// 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 需要再主线程等待一个异步任务返回,才能继续执行下面的逻辑,但是又不希望堵塞用户事件。
|
请发表评论