ios swift多线程的实现 Multithreading

1、多线程的概念

Multithreading多线程是指从软件或硬件上,实现多个线程并发执行的技术。使得能够同步完成多项任务,提高资源使用效率。


1.1 任务、进程和线程

  • 任务Task:应用程序完成的一个活动,一个task既可以是一个进程,也可以是一个线程;
  • 进程Process:系统进行资源分配和调度的一个独立单位,在内存中有完备的数据空间和代码空间;
  • 线程Thread:进程中的一个实体,CPU调度和分派的基本单位;


1.2 线程的Stack space

系统中每一个进程都有自己的内存空间,同个进程中多个线程共用进程的内存空间。

  • 在Mac OS中,主线程的栈空间为8MB;
  • 在Ios中,主线程的栈空间为1MB;

应用程序子线程默认栈空间大小为512KB,子线程允许分配的最小栈空间为16KB,并且必须是4KB的整数倍。开发者可以通过NSThread线程对象的stacksize来修改一个子线程的栈空间。

let thread = Thread.init(target: self, selector:(VIewController.threadAction),object:nil)
thread.stackSize = 1024*1024


1.3 线程的优先级

  • threadPriority: 0.0-1.0
  • 系统默认优先级是0.5
  • 高优先级并不是100%比低优先级先执行,只是得到CPU调度的纪律更高
1.4 线程的生命周期
  • 创建 对线程对象进行初始化;
  • 就绪 添加到线程池,等待CPU的调度;
  • 运行 是线程处于执行状态;
  • 阻塞 可以是线程休眠至指定的时间点,或者通过Lock给线程加锁;
  • 消亡 执行完毕之后自动处于正常消亡状态;
2、三种常用的多线程技术
2.1 Thread

var imageView = UIImageView()
    var label = UILabel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        imageView = UIImageView(frame: CGRect(x: 0, y: 120, width: 320, height: 300))
        self.view.addSubview(imageView)
        
        label = UILabel(frame: CGRect(x: 0, y: 120, width: 320, height: 300))
        label.backgroundColor = UIColor.lightGray
        label.textAlignment = .center
        label.text = "Loading..."
        label.font = UIFont.systemFont(ofSize: 42)
        self.view.addSubview(label)
        
        let imageUrl = "http://images.apple.com/v/iphone/home/s/home/images/trade_in_iphone_large_2x.jpg"
        let thread = Thread(target: self, selector: #selector(ViewController.downloadImage), object: imageUrl)
        thread.start()
    }
    
    func downloadImage(path : String){
        let url = URL(string: path)
        var data : Data!
        do{
            try data = Data(contentsOf: url!)
            let image = UIImage(data: data)
            self.perform(#selector(ViewController.showImage), on: Thread.main, with: image, waitUntilDone: true)
        }catch{
            print("下载图片失败。")
        }
    }
    
    func showImage(image : UIImage){
        self.imageView.image = image
        self.label.isHidden = true
    }



2.2 Operation
override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        topImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 320, height: 280))
        self.view.addSubview(topImageView)
        
        footImageView = UIImageView(frame: CGRect(x: 0, y: 280, width: 320, height: 290))
        self.view.addSubview(footImageView)
        
        let downloadA = getOperation(name: "下载线程A", imageUrl: "http://images.apple.com/v/watch/k/images/overview/watch_03_large.jpg", isTopOne: true)
        
        let downloadB = getOperation(name: "下载线程B", imageUrl: "http://images.apple.com/v/watch/k/images/overview/watch_05_large.jpg", isTopOne: false)
        
        let queue = OperationQueue()
        queue.maxConcurrentOperationCount = 1
        queue.addOperation(downloadA)
        queue.addOperation(downloadB)
        
        for operation in queue.operations{
            print("Operation名称:"+operation.name!)
        }
    }
    
    func getOperation(name : String, imageUrl : String, isTopOne : Bool) -> BlockOperation{
        let download = BlockOperation(block: {_ in
            let url = URL(string: imageUrl)
            var data : Data!
            do{
                Thread.sleep(forTimeInterval: 1.0)
                try data = Data(contentsOf: url!)
                let image = UIImage(data: data)
                if isTopOne{
                    self.perform(#selector(ViewController.showTopImage), on: Thread.main, with: image, waitUntilDone: true)
                }
                else{
                    self.perform(#selector(ViewController.showFootImage), on: Thread.main, with: image, waitUntilDone: true)
                }
            }catch{
                print("下载图片失败。")
            }
        })
        download.name = name
        return download
    }
    
    func showTopImage(image : UIImage){
        self.topImageView.image = image
    }
    
    func showFootImage(image : UIImage){
        self.footImageView.image = image
    }




2.3 Grand Central Dispatch
override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        label.frame = CGRect(x: 0, y: 0, width: 320, height: 568)
        label.text = "Loading..."
        label.font = UIFont(name: "Arial", size: 24)
        label.backgroundColor = UIColor.orange
        label.numberOfLines = 0
        label.lineBreakMode = NSLineBreakMode.byWordWrapping
        self.view.addSubview(label)
        
        let apiURL = URL(string: "http://ip.taobao.com/service/getIpInfo.php?ip=27.156.152.57")
        
        let globalQueue = DispatchQueue.global()
        globalQueue.async{
            let result = try? Data(contentsOf: apiURL!)
            let message  = String(data: result!, encoding: String.Encoding.utf8)
            DispatchQueue.main.async
            {
                self.label.text = message
            }
        }
    }

3、总结
  • Thread(基于thread):每个Thread对象对应一个线程,优点是量级较轻,使用简单,缺点是需要开发者自行管理线程的生命周期、线程同步、加锁解锁、睡眠以及唤醒等操作。
  • Operation(基于queue):不需要关心线程的管理和线程同步的事情,可以把精力放在自己需要执行的业务逻辑上,缺点是只能实现它或者使用它定义好的子类。
  • Grand Central Dispatch(task):基于C语言的一种高效、强大的多核编辑解决方案,其在后端管理着一个线程池,它不仅仅决定代码块将在那个线程被执行,还可以根据可用的系统资源对这些线程进行管理。
开发者在多线程技术进行选择时,如果追求简便、安全,可以选择基于队列的Operation技术。如果需要处理大量并发数据,同时又追求应用程序的性能和效率,可以选择Grand Central Dispatch。









posted @ 2017-08-16 09:33  柳玉豹  阅读(161)  评论(0)    收藏  举报