異步函數(shù):異步和代碼的組合,在函數(shù)聲明的返回箭頭前面,加上asyn關(guān)鍵字,就可以把一個(gè)函數(shù)聲明為異步函數(shù):
func upload(result: Double) async -> String {
"OK"
}
async關(guān)鍵字會(huì)幫助編譯器做兩個(gè)事情:
1、它允許我們?cè)诤瘮?shù)體內(nèi)部使用await關(guān)鍵字;
2、它要求其他人在調(diào)用這個(gè)函數(shù)時(shí),使用await關(guān)鍵字。
列:從服務(wù)器獲取數(shù)據(jù),求數(shù)據(jù)的平均值,再發(fā)送給服務(wù)器
常規(guī)代碼:
func fetchWeatherHistory(completion: @escaping ([Double]) -> Void) {
// 用隨機(jī)值來(lái)取代網(wǎng)絡(luò)請(qǐng)求返回的數(shù)據(jù)
DispatchQueue.global().async {
let results = (1...100_000).map { _ in Double.random(in: -10...30) }
completion(results)
}
}
func calculateAverageTemperature(for records: [Double], completion: @escaping (Double) -> Void) {
// 先求和再計(jì)算平均值
DispatchQueue.global().async {
let total = records.reduce(0, +)
let average = total / Double(records.count)
completion(average)
}
}
func upload(result: Double, completion: @escaping (String) -> Void) {
// 省略上傳的網(wǎng)絡(luò)請(qǐng)求代碼,均返回"OK"
DispatchQueue.global().async {
completion("OK")
}
}
調(diào)用實(shí)現(xiàn):
fetchWeatherHistory { [weak self] records in
self?.calculateAverageTemperature(for: records) { average in
self?.upload(result: average) { response in
print("Server response: \(response)")
}
}
}
是不是感覺(jué)嵌套很復(fù)雜冗余。
async/await實(shí)現(xiàn):
func fetchWeatherHistory() async -> [Double] {
(1...100_000).map { _ in Double.random(in: -10...30) }
}
func calculateAverageTemperature(for records: [Double]) async -> Double {
let total = records.reduce(0, +)
let average = total / Double(records.count)
return average
}
func upload(result: Double) async -> String {
"OK"
}
調(diào)用實(shí)現(xiàn):
func processWeather() async {
let records = await fetchWeatherHistory()
let average = await calculateAverageTemperature(for: records)
let response = await upload(result: average)
print("Server response: \(response)")
}
在viewDidLoad中調(diào)用:
注意:
1、我們調(diào)用async方法的時(shí)候必須是在異步線程中,這里我們使用Task
2、調(diào)用帶有async方法時(shí)前面必須帶有await關(guān)鍵字
Task {
await processWeather()
}
在使用多線程我們會(huì)出現(xiàn)兩種情況,兩個(gè)異步操作有先后關(guān)系,還有一種就是等兩個(gè)異步函數(shù)同時(shí)完成再進(jìn)行下一步操作,這兩個(gè)異步函數(shù)時(shí)同時(shí)進(jìn)行的。
有依賴關(guān)系的異步函數(shù)(異步串行):
func processFromScratch() async {
let strings = await loadFromDatabase()
let signature = await loadSignature()
print("finished")
}
并發(fā)異步函數(shù)(異步并行):
func processFromScratch() async {
async let loadStrings = loadFromDatabase()
async let loadSignature = loadSignature()
let strings = await loadStrings
let signature = await loadSignature
print("finished")
}
除此之外異步我們也可以像gcd使用group:
func someSyncMethod() {
Task {
await withThrowingTaskGroup(of: Void.self) { group in
group.async {
try await self.loadResultRemotely()
}
group.async {
try await self.processFromScratch()
}
}
print("Done: \(results)")
}
}
之前多線程訪問(wèn)同一個(gè)屬性是不安全的我們可以用線程鎖來(lái)保證線程安全,在swift5.5中引入了actor,在概念上類似于在并發(fā)環(huán)境中可以安全使用的類,即需要確保在任何時(shí)間只能由單個(gè)線程訪問(wèn)actor內(nèi)的可變狀態(tài),跟類一樣屬于引用類型,跟類有差別的是不能繼承。
actor SafeCollector {
var deck: Set<String>
init(deck: Set<String>) {
self.deck = deck
}
func send(card selected: String, to person: SafeCollector) async -> Bool {
guard deck.contains(selected) else { return false }
deck.remove(selected)
await person.transfer(card: selected)
return true
}
func transfer(card: String) {
deck.insert(card)
}
}
多線程獲取屬性deck是線程安全的。