我不是罗大锤我不是罗大锤

我不是罗大锤

我不是罗大锤我不是罗大锤

我不是罗大锤

首页首页
分类分类
标签标签
友情链接友情
日记日记
Swift 结构化并发简单使用和与 Kotlin 协程对比Swift 结构化并发简单使用和与 Kotlin 协程对比

Swift 结构化并发简单使用和与 Kotlin 协程对比

&Swift#Swift#Kotlin

允许评论

7 个月前

最新在学习 Swift 并发的一些操作,这里记录一下一些常见的用法和与 Kotlin 协程的一些差异。仅涉及一些简单的基础操作。

目前 Swift 中的异步和线程相关的功能主要分为两套体系:

  1. GCD (Grand Central Dispatch): 核心类有 DispatchQueue, DispatchGroup, DispatchSemaphore 等。
  2. Swift Concurrency (Swift 5.5+): 新引入的异步模型,使用 Task, async/await, Actor 等。

一、主线程 vs 后台线程

1. 切换到主线程

Kotlin 协程:

withContext(Dispatchers.Main) {
  // 更新 UI
  textView.text = "Hello"
}

Swift (GCD):

DispatchQueue.main.async {
  // 更新 UI
  self.label.text = "Hello"
}

2. 切换到后台线程

Kotlin 协程:

withContext(Dispatchers.IO) {
  val data = fetchData()
}

Swift (GCD):

DispatchQueue.global(qos: .background).async {
  let data = fetchData()

  // 切回主线程
  DispatchQueue.main.async {
    self.label.text = "Data loaded"
  }
}
  1. DispatchQueue.main: 主队列(串行队列),可以用于与 UI 交互,类似于 Kotlin 中的 Dispatchers.Main。
  2. DispatchQueue.global(): 全局并发队列(默认优先级为 .default),适合执行非 UI 任务(如网络请求、计算等),多个任务并行执行。
  3. DispatchQueue.global(qos: .background): 全局并发队列,指定 Quality of Service (QoS) 优先级。其中 Qos 优先级从高到低如下所示:
    1. .userInteractive: 用户交互任务
    2. .userInitiated: 用户触发的任务
    3. .default: 默认优先级
    4. .utility: 后台任务(如下载)
    5. .background: 最低优先级

二、并发执行多任务

Kotlin 协程:

private val scope = CoroutineScope(Dispatchers.IO)
val job1 = scope.async { fetchData1() }
val job2 = scope.async { fetchData2() }

val res1 = job1.await()
val res2 = job2.await()
// 或
val resultList = awaitAll(job1, job2)

println("Result: $res1, $res2")

Swift (GCD + DispatchGroup):

let group = DispatchGroup()

var res1: String?
var res2: String?

DispatchQueue.global().async(group: group) {
  res1 = fetchData1()
}

DispatchQueue.global().async(group: group) {
  res2 = fetchData2()
}

group.notify(queue: .main) {
  print("Result: \(res1), \(res2)")
}

DispatchGroup 用于管理一组任务的完成状态,当所有任务完成后触发回调(notify)。

DispatchGroup 的核心方法如下:

  1. enter(): 标记一个任务开始。
  2. leave(): 标记一个任务完成。
  3. notify(queue:execute:): 所有任务完成后,在指定队列执行回调。

简单代码示例:

let group = DispatchGroup()

// 任务 1
group.enter()
DispatchQueue.global().async {
  fetchData1()
  group.leave()
}

// 任务 2
group.enter()
DispatchQueue.global().async {
  fetchData2()
  group.leave()
}

// 所有任务完成后回调
group.notify(queue: .main) {
  print("All done")
}

三、线程安全(线程锁)

Kotlin:

private val lock = Mutex()
private var counter = 0

suspend fun updateCounter() {
  lock.withLock {
    counter++
  }
}

// 或者
private val lock = Any()

fun updateCounter() {
  synchronized(lock) {
    counter++
  }
}

Swift:

private let lock = NSLock()
private var counter = 0

func updateCounter() {
  lock.lock()
  counter += 1
  lock.unlock()
}

// 或者使用 DispatchQueue 作为串行队列
private let queue = DispatchQueue(label: "com.example.queue")

func updateCounter() {
  queue.async {
    counter += 1
  }
}

DispatchQueue vs NSLock 的使用场景:

  1. NSLock: 传统的互斥锁,直接控制临界区。轻量级,适合简单、短时间的锁操作。
  2. DispatchQueue: 串行队列,通过串行队列确保任务顺序执行。适合复杂逻辑或需要异步执行的场景。
    1. DispatchQueue(label: "test"): 串行队列,任务按提交顺序依次执行。
    2. DispatchQueue.global() 或 DispatchQueue(label: "test", attributes: .concurrent): 并发队列。

四、async / await

Swift 在 5.5+ 引入了 async/await 机制,下面记录一些简单用法。

1. 定义异步函数

Kotlin (suspend):

suspend fun fetchData(): String {
  delay(1000)
  return "Data"
}

Swift (async):

func fetchData() async -> String {
  try? await Task.sleep(nanoseconds: 1_000_000_000)
  return "Data"
}

2. 调用异步函数

Kotlin:

viewModelScope.launch {
  val data = fetchData()
  textView.text = data
}

Swift (Task):

Task {
  let data = await fetchData()
  self.label.text = data
}

3. 网络交互示例

下面会使用 Task、async / await 编写一个简单的网络请求和回调更新 UI 的示例。

// 异步函数,从云端获取数据
func fetchDataFromCloud() async throws -> Data {
  let url = URL(string: "https://api.example.com/data")!
  let (data, _) = try await URLSession.shared.data(from: url)
  return data
}

// 异步函数,提交数据到云端
func submitDataToServer(_ data: Data) async throws {
  let url = URL(string: "https://api.example.com/submit")!
  var request = URLRequest(url: url)
  request.httpMethod = "POST"
  request.httpBody = data
  _ = try await URLSession.shared.data(for: request)
}

// 用户点击事件(假设在主线程调用)
func onClick() {
  Task {
    do {
      // 1. 从云端获取数据
      let data = try await fetchDataFromCloud()
      
      // 2. 更新 UI(切回主线程)
      await MainActor.run {
        updateUI(with: data) // 假设的 UI 更新方法
      }
      
      // 3. 用户触发提交数据(后台线程)
      try await submitDataToServer(data)
      
      // 4. 提交完成后提示用户(主线程)
      await MainActor.run {
        successAlert()
      }
    } catch {
      await MainActor.run {
        errorAlert(error)
      }
    }
  }
}

Task 会自动管理异步任务的执行和线程切换。

await 会挂起当前线程(在例子中非阻塞),直到异步操作完成。

MainActor.run 会确保代码块在主线程中执行(类似 DispatchQueue.main.async)

五、Actor

Actor 是 Swift 5.5+ 引入的线程安全机制,用于解决数据竞争问题,它的核心是隔离,确保内部状态(属性)只能通过异步方法访问,从而避免并发访问冲突。

Actor 的核心特征如下:

  1. 隔离访问:Actor 的属性和方法默认只能在 Actor 内部直接访问。
  2. 串行执行:Actor 内部的任务按顺序执行。
  3. 编译时检查:编译器会强制要求通过 await 调用 Actor 方法,防止直接并发访问。

下面是一个使用 Actor 的线程安全的计数器例子:

actor Counter {
  private var value = 0
  
  func increment() {
    value += 1
  }
  
  func getValue() -> Int {
    return value
  }
}

// 使用方式
let counter = Counter()

Task {
  // ❌ 错误用例
  counter.increment()
  // 编译器报错:Expression is 'async' but is not marked with 'await'
  
  
  // ✅ 正确用例
  await counter.increment()
  print(await counter.getValue()) // 1
}
目录
一、主线程 vs 后台线程
1. 切换到主线程
2. 切换到后台线程
二、并发执行多任务
三、线程安全(线程锁)
四、async / await
1. 定义异步函数
2. 调用异步函数
3. 网络交互示例
五、Actor
Take a look

Take a look

6 个月前
Wow that was odd. I just wrote an very long comment but after I clicked submit my comment didn't show up. Grrrr... well I'm not writing all that over again. Anyway, just wanted to say fantastic blog!
Take a look

Take a look

6 个月前
Wow that was odd. I just wrote an very long comment but after I clicked submit my comment didn't show up. Grrrr... well I'm not writing all that over again. Anyway, just wanted to say fantastic blog!
Take a look

Take a look

6 个月前
Wow that was odd. I just wrote an very long comment but after I clicked submit my comment didn't show up. Grrrr... well I'm not writing all that over again. Anyway, just wanted to say fantastic blog!

Total 3

    1
  • 1

在线人数:0 人

文章总浏览量:21958

Powered byNola