異步函數(shù):異步和代碼的組合,在函數(shù)聲明的返回箭頭前面雳旅,加上asyn關(guān)鍵字跟磨,就可以把一個函數(shù)聲明為異步函數(shù):
func upload(result: Double) async -> String {
"OK"
}
async關(guān)鍵字會幫助編譯器做兩個事情:
1、它允許我們在函數(shù)體內(nèi)部使用await關(guān)鍵字攒盈;
2抵拘、它要求其他人在調(diào)用這個函數(shù)時,使用await關(guān)鍵字型豁。
列:從服務(wù)器獲取數(shù)據(jù)僵蛛,求數(shù)據(jù)的平均值,再發(fā)送給服務(wù)器
常規(guī)代碼:
func fetchWeatherHistory(completion: @escaping ([Double]) -> Void) {
// 用隨機(jī)值來取代網(wǎng)絡(luò)請求返回的數(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) {
// 先求和再計算平均值
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ò)請求代碼迎变,均返回"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)")
}
}
}
是不是感覺嵌套很復(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方法的時候必須是在異步線程中氏豌,這里我們使用Task
2喉酌、調(diào)用帶有async方法時前面必須帶有await關(guān)鍵字
Task {
await processWeather()
}
在使用多線程我們會出現(xiàn)兩種情況,兩個異步操作有先后關(guān)系泵喘,還有一種就是等兩個異步函數(shù)同時完成再進(jìn)行下一步操作泪电,這兩個異步函數(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)")
}
}
之前多線程訪問同一個屬性是不安全的我們可以用線程鎖來保證線程安全纪铺,在swift5.5中引入了actor相速,在概念上類似于在并發(fā)環(huá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是線程安全的芜繁。