多線程 是一個應用程序內多個代碼的執行路徑,執行線程,同時在同一時間裏執行不一樣的任務。編程
三種:swift
一、NSTread多線程
二、Cocoa NSOperation (NSOperation,NSOperationQueue)併發
三、GrandCentralDispatch:GCD異步
1\NSTreadasync
相對最簡單,須要本身管理線程的生命週期和線程同步(加鎖會有必定的系統開銷)ide
兩種應用方式:性能
須要傳遞三個參數:spa
selector:線程執行方法""線程
target:方法所在的對象
argument:傳遞給方法的參數,可選nil
1、直接建立線程,自動運行線程
// Class Method
class func detachNewThreadSelector(selector:Selector,toTarget target:AnyObject,withObject argument:AnyObject?)
2、先建立一個線程對象,手動運行線程,在運行以前可設置線程優先級等信息。
convenience init(target:AnyObject,selector:Selector,object argument:AnyObject?)
for example
// download image method
func downloadImage()
{
var imageUrl = "https://www.baidu.com/img/bdlogo.png"
var data = NSData.dataWithContentsOfURL(NSURL.URLWithString(imageUrl),options:nil,error:nil)
println(data.length)
}
override func viewDidLoad(){
super.viewDidLoad()
// 第一種方式
NSThread.detachNewThreadSelector("downloadImage",toTarget:self,withObject:nil)
// 第二種方式
var downloadImageThread = NSThread(target:self,selector:"downloadImage",object:nil)
dowloadImageThread.start()
}
線程同步,經過鎖來實現,每一個線程有一個鎖,鎖 與 特定的線程關聯。
for example
// 定義兩個線程
var thread1,thread2:NSThread?
// 線程條件
let condition1 = NSCodition()
let condition2 = NSCodition()
// two method for thread
func method1(sender: AnyObject)
{
for var i = 0; i <10; i++
{
println("thread 1 running \(i)")
sleep(1)
if i == 2
{
thread2!.start()
// lock
condition1.lock()
condition1.wait()
condition1.unlock()
}
}
println(thread 1 over)
//
condition2.signal()
}
//
func method2(sender:AnyObject)
{
for var i=0;i<10;i++
{
println("thread 2 running \(i)")
sleep(1)
if i ==2
{
// active thread 1
condition1.signal()
// lock
condition2.lock()
condition2.wait()// stop waitting
condition2.unlock()
}
}
println("thread 2 over")
}
// RUN
thread2 = NSThread (target:self , selector:"method2:",object:nil)
thread1 = NSThread(target:self,selector:"method1",object:nil)
控制檯輸出
thread 1 running 0
thread 1 running 1
thread 1 running 2
thread 2 running 0
thread 2 running 1
thread 2 running 2
thread 1 running 3
thread 1 running 4
thread 1 running 5
thread 1 running 6
thread 1 running 7
thread 1 running 8
thread 1 running 9
thread 1 over
thread 2 running 3
thread 2 running 4
thread 2 running 5
thread 2 running 6
thread 2 running 7
thread 2 running 8
thread 2 running 9
線程1 2是同步關係,啓動2,掛起 1,激活1,掛起2,有效避免了線程1佔用一個資源時,引發線程2不能訪問的問題。
NSOperation 兩種方式
一 兩個子類 NSInvocationOperation NSBlockOperation
// creat instance
var operation = NSInvocationOperation(target:self,selector:"dowloadImage",object:nil)
var queue = NSOperationQueue()
queue.addOperation(operation)
後臺創建一個線程
Queue隊列中能夠加入不少個operation 能夠把它看作是一個線程池子,能夠設置線程池中的線程數,即併發操做數。
默認是:-1,-1表示沒有限制,同時運行隊列中的所有操做。
queue.maxConcurrentOperationCount = 6
// ervery operation come to an end
var completionBlock:(()->Void)?
operation.completionBlock = completionBlock
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,4),dispatch_get_main_queue(),{println("complete")})
// cancell
queue.cancelAllOperations()
二 繼承NSOperation 把子類的對象放到NSOperationQueue隊列中 ,一旦加入,就處理這個,直到操做完成,隊列被釋放。
// creat DrinkOperation.swift 繼承 NSOperation 且 實現main方法
import UIKit
class DrinkOperation:NSOperation{
override func main()
{
println("drink")
}
}
// e.g.
// creat a instance
var queue1 = NSOperationQueue()
// creat a operation
var drinkOperation = DrinkOperation()
// add
queue1.addOperation(drinkOperation)
Grand Central Dispatch
多核編程
底層也是用線程實現,queue能夠接受任務,先到先執行順序來執行,也能夠併發或串行執行。
同步或異步
優勢多多:基於C,融入面向對象,Block,易用,性能上自動根據系統負載來增減線程數量,無需加鎖。
三種方法:
一 本身建立隊列
func dispatch_queue_create(label:UnsafePointer<Int8>,attr:dispation_queue_attr_t!)->dispatch_queue_t!
label:參數表明隊列名稱,能夠任意名
DISPATCH_QUEUE_CONCURRENT 並行
DISPATCH_QUEUE_SERIAL 串行
//e.g.
var serialQueue = dispatch_queue_create("serialQueue_1",DISPATCH_QUEUE_SERIAL)
var concurrentQueue = dispatch_queue_create("concurrentQueue_1",DISPATCH_QUEUE_CONCURRENT)
二 獲取系統的全局隊列
func dispatch_get_global_queue(identifier:Int,flags:UInt)->dispatch_gueue_t!
參數 identifier 執行優先級 ,4個優先級
DISPATCH_QUEUE_PRIORITY_HIGH
DISPATCH_QUEUE_PRIORITY_DEFAULT
DISPATCH_QUEUE_PRIORITY_LOW
DISPATCH_QUEUE_PRIORITY_BACKGROUND 很是低的有相機,用於不太關心的後臺任務
// e.g.
var globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)
三 在主線程的Main dispatch queue
在主線程裏執行的隊列(只有一個主線程)
一切跟UI相關的操做都放到主線程中執行
func dispatch_get_main_queue()->dispatch_queue_t!
// e.g.
var mainQueue = dispatch_get_main_queue()
追加任務到隊裏的 兩個方法:
一 dispatch_async 異步追加Block
async = asynchronous 異步
func dispatch_async(queue:dispatch_queue_t!,block:dispatch_block_t!)
第一個參數:GCD隊列
第二個參數:block
// e.g.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),{()->Void in
// 耗時代碼塊
//執行完 調用主線程刷新界面
dispatch_async(dispatch_get_main_queue(),{()->Void in
//通知主線程刷新
})
})
二 dispatch_sync 同步追加Block
與以前相反,block結束以前,dispatch_sync會一直等待,等待隊列前面的全部任務完成後才執行追加的任務。
func dispatch_sync()
// e.g.
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),{()->Void in
println("sync1")
})
加到 global_queue異步隊列中,不會形成鎖死,但會一直等待代碼執行完畢。
若是加到main_queue中,在主線程中添加任務操做,就會引發死鎖。
// e.g.
dispatch_sync(dispatch_get_main_queue(),{()->Void in
print("sync2")
})
暫停和繼續執行隊列
func dispatch_suspend() 暫停
func dispatch_resume() 繼續
suspend 使 suspension reference count +1
resume -1
count>0 queue就保持掛起狀態
若是掛起了 一個 queue 或者 source 那麼銷燬他以前,先對其進行恢復。
var concurrentQueue = dispatch_queue_create("concurrentQueue_1",DISPATCH_QUEUE_CONCURRENT)
// stop
dispatch_suspend(concurrentQueue)
// go on
dispatch_resume(concurrentQueue)
只執行一次 用於單例
dispatch_once
延時:指定時間後把任務追加到 dispatch queue裏面
dispatch_after
func dispatch_time(when:XX,delta:Int64)->dispatch_time_t
delta單位很是小,到秒要乘以 NSEC_PER_SEC
let deltaT = 2.0 *Double(NSEC_PER_SEC)
let dTime =dispatch_time(DISPATCH_TIME_NOW,Int64(deltaT))
dispatch_after(dTime,dispatch_get_global-global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)
{()->Viod in
println("延時2秒執行")
})
多個任務都結束的一個所有結束:dispatch_barrier_async
當執行任務更新數據時,會出現數據不同的狀況。
for i in 1...100
{
dispatch_async(queue,{()->Void in
println("\(i)")
})
}
雖然使用dispatch_barrier_async能夠避免
可是有另外一方法, semaphore 信號量
var semaphore = dispatch_semaphore_creat(1)//初始值爲1
for i in 1...100
{
dispatch_async(queue,{()->Void in
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER)
println("\(i)")
dispatch_semaphore_signal(semaphore)
})
}