• swift5.x 多线程的应用场景


    //
    //  ViewController17.swift
    //  swiftT
    //
    //  Created by wjwdive on 2020/6/3.
    //  Copyright © 2020 wjwdive. All rights reserved.
    //
    
    import UIKit
    
    class ViewController17: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            //线程不安全的示例
    //        noThreadSafeSimple()
            //线程安全的示例
            ThreadSafeSimple()
            //线程安全的 优化读写操作示例
            betterThreadSafeArraySimple()
        }
    
    }
    
    //多线程的应用场景
    //1 一个也没有三个网络请求,需要再三个网络请求返回的时候刷新界面
    //2 需要一个线程安全的Array的读写
    //3 编写一个多线程下载器,可执行多个下载任务,每个任务可以保存当下下载的字节数,总字节数,可以设置回调得到当前下载进度
    //4 需要再主线程等待一个异步任务返回,才能继续执行下面的逻辑,但是又不希望堵塞用户事件。
    
    //1 一个也没有三个网络请求,需要再三个网络请求返回的时候刷新界面
    //实现:
    // 三个网络请求分别是一个Operation,刷新界面是一个Operation,刷新界面的Operation依赖三个网络请求的Operation。这样就能保证三个网络请求都成功之后才刷新界面。
    
    
    //2 需要一个线程安全的Array的读写
    // 不做线程安全处理出错的示例:
    //线程A
    //线程B
    //1⃣️线程A获取Array的长度length
    //2⃣️线程B删除了Array的最后一个元素
    //3⃣️线程A根据length 读取Array的最后一个元素,这时就会出错
    
    
    //线程不安全的示例:
    func noThreadSafeSimple() {
        //线程不安全的示例
        var array = Array(0...10000)
        func getLastItem() -> Int? {
            var temp: Int? = nil
            if array.count > 0 {
                temp = array[array.count - 1] //这行代码在获取array长度之后,可能中间有另一个线程在remove元素,之后在取最后一个元素,出现数组越界。
            }
            return temp
        }
        
        func removeLastItem() {
            array.removeLast()
        }
        
        let queue = DispatchQueue(label:"queue1")
        queue.async {
            for _ in 0..<10000 {
                removeLastItem()
            }
        }
        let queue2 = DispatchQueue(label:"queue2")
    
        queue2.async {
            for _ in 0..<10000 {
                if let item = getLastItem() {
                    print(item)
                }
            }
        }
        
    }
    
    //安全的Array示例:
    func ThreadSafeSimple() {
        //线程安全的示例
        var array = Array(0...10000)
        let lock = NSLock()//加锁
        func getLastItem() -> Int? {
            var temp: Int? = nil
            lock.lock()
            if array.count > 0 {
                temp = array[array.count - 1] //这行代码在获取array长度之后,可能中间有另一个线程在remove元素,之后在取最后一个元素,出现数组越界。
            }
            lock.unlock()//解锁
            return temp
        }
        
        func removeLastItem() {
            lock.lock()
            array.removeLast()
            lock.unlock()
        }
        
        let queue = DispatchQueue(label:"queue1")
        queue.async {
            for _ in 0..<10000 {
                removeLastItem()
            }
        }
        let queue2 = DispatchQueue(label:"queue2")
    
        queue2.async {
            for _ in 0..<10000 {
                if let item = getLastItem() {
                    print(item)
                }
            }
        }
        
    }
    
    
    //如果在一段时间内只有只读操作,我们是不需要加锁的。而上述NSLock的方式仍然强制每次读操作都加锁等待,对性能造成不小的影响,尤其是我们对数组的操作远远多于写操作的时候,这个性能的影响就相当可观,那么该如何优化呢?
    //优化:
    // 一个队列加两个方法
    //1 首先是并行队列,既然我们要保持多线程环境并行操作的优势,那我们肯定要选择并行队列。
    //2 二是sync方法,这个方法来封装我们的读操作,读操作的发起方需要在调用读方法的时候能直接拿到返回值,而不是在异步回调里面获取。
    //3 三是async方法适用barrier flag, z这个方法来封装我们的鞋操作,这个方法起到一个栅栏的作用,它等待所有位于 barrier async函数之前的操作执行完毕后执行,并且在barrier async函数执行后,barrier async函数之后的操作才会得到执行
    func betterThreadSafeArraySimple() {
        var array = Array(0...10000)
        var concurrentQueue = DispatchQueue(label: "concurrent queue", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)
        
        func getLastItem() -> Int? {
            var temp: Int? = nil
            concurrentQueue.sync {
                if array.count > 0 {
                    temp = array[array.count - 1]
                }
            }
            return temp
        }
        
        func removeLastItem() {
            let workItem = DispatchWorkItem(qos: DispatchQoS.default, flags: DispatchWorkItemFlags.barrier) {
                array.removeLast()
            }
            concurrentQueue.async(execute: workItem)
        }
    }
    
    
  • 相关阅读:
    2.分布式锁
    1. junit用法,before,beforeClass,test,after, afterClass的执行顺序
    GC算法
    记一次"截图"功能的前期调研过程!
    程序员转行手册!
    Yarn详细的工作流程
    Yarn的三种调度器(Scheduler)
    Hadoop序列化与Java序列化的区别
    MapReduce执行过程
    从普通登录到单点登录图例
  • 原文地址:https://www.cnblogs.com/wjw-blog/p/13038567.html
Copyright © 2020-2023  润新知