Swift5.5 async,await實(shí)現(xiàn)多線程

異步函數(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是線程安全的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容