异步函数:异步和代码的组合,在函数声明的返回箭头前面,加上asyn关键字,就可以把一个函数声明为异步函数:
func upload(result: Double) async -> String {
"OK"
}
async关键字会帮助编译器做两个事情:
1、它允许我们在函数体内部使用await关键字;
2、它要求其他人在调用这个函数时,使用await关键字。
列:从服务器获取数据,求数据的平均值,再发送给服务器
常规代码:
func fetchWeatherHistory(completion: @escaping ([Double]) -> Void) {
// 用随机值来取代网络请求返回的数据
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) {
// 省略上传的网络请求代码,均返回"OK"
DispatchQueue.global().async {
completion("OK")
}
}
调用实现:
fetchWeatherHistory { [weak self] records in
self?.calculateAverageTemperature(for: records) { average in
self?.upload(result: average) { response in
print("Server response: \(response)")
}
}
}
是不是感觉嵌套很复杂冗余。
async/await实现:
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"
}
调用实现:
func processWeather() async {
let records = await fetchWeatherHistory()
let average = await calculateAverageTemperature(for: records)
let response = await upload(result: average)
print("Server response: \(response)")
}
在viewDidLoad中调用:
注意:
1、我们调用async方法的时候必须是在异步线程中,这里我们使用Task
2、调用带有async方法时前面必须带有await关键字
Task {
await processWeather()
}
在使用多线程我们会出现两种情况,两个异步操作有先后关系,还有一种就是等两个异步函数同时完成再进行下一步操作,这两个异步函数时同时进行的。
有依赖关系的异步函数(异步串行):
func processFromScratch() async {
let strings = await loadFromDatabase()
let signature = await loadSignature()
print("finished")
}
并发异步函数(异步并行):
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,在概念上类似于在并发环境中可以安全使用的类,即需要确保在任何时间只能由单个线程访问actor内的可变状态,跟类一样属于引用类型,跟类有差别的是不能继承。
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是线程安全的。