面向 Swift 开发者的 Flutter 并发
在学习 Flutter 和 Dart 时发挥你的 Swift 并发知识。
Dart 和 Swift 都支持并发编程。本指南帮助你理解 Dart 中的并发机制及其与 Swift 的对比。掌握这些后,你可以构建高性能 iOS 应用。
在 Apple 生态中开发时,某些任务可能耗时较长,例如获取或处理大量数据。iOS 开发者通常使用 Grand Central Dispatch(GCD)通过共享线程池调度任务:将任务加入 dispatch 队列,由 GCD 决定在哪条线程执行。
但 GCD 会创建线程处理剩余工作项,可能导致线程过多、系统过载。Swift 的结构化并发模型减少了线程数和上下文切换,现在每个核心只有一条线程。
Dart 采用单线程执行模型,支持 Isolate、事件循环和异步代码。Isolate 是 Dart 对轻量线程的实现。除非你 spawn 一个 Isolate,否则 Dart 代码在由事件循环驱动的主 UI 线程中运行。Flutter 的事件循环相当于 iOS 主循环,即附加在主线程上的 Looper。
Dart 的单线程模型并不意味着你必须把所有操作都作为阻塞操作导致 UI 冻结,而应使用 Dart 提供的异步特性,例如 async/await。
异步编程
#
异步操作允许其他操作在其完成前执行。Dart 和 Swift 都使用 async 和 await 关键字支持异步函数:async
标记函数执行异步工作,await 告诉系统等待函数返回结果,这意味着 Dart VM 可能 在必要时挂起该函数。有关异步编程的更多细节,请参阅 Concurrency in Dart(Dart 中的并发)。
利用主线程 / 主 isolate
#在 Apple 操作系统上,主线程是应用开始运行的地方,用户界面渲染始终在主线程进行。Swift 与 Dart 的一个区别是 Swift 可能对不同任务使用不同线程,且不保证使用哪条线程,因此在 Swift 中调度 UI 更新时可能需要确保工作发生在主线程。
假设你要编写一个异步获取天气并显示结果的函数。
在 GCD 中,若要手动将进程派发到主线程,可以这样做。
首先定义 Weather enum:
enum Weather: String {
case rainy, sunny
}
接下来定义 view model,标记为 @Observable,发布类型为
Weather? 的 result。使用 GCD 创建后台 DispatchQueue 将工作发送到线程池,再派回主线程更新
result。
@Observable class ContentViewModel {
private(set) var result: Weather?
private let queue = DispatchQueue(label: "weather_io_queue")
func load() {
// Mimic 1 second network delay.
queue.asyncAfter(deadline: .now() + 1) { [weak self] in
DispatchQueue.main.async {
self?.result = .sunny
}
}
}
}
最后显示结果:
struct ContentView: View {
@State var viewModel = ContentViewModel()
var body: some View {
Text(viewModel.result?.rawValue ?? "Loading...")
.onAppear {
viewModel.load()
}
}
}
近年来 Swift 引入 actors 以支持共享可变状态的同步。要确保工作在主线程执行,可定义标记为 @MainActor 的 view model 类,其
load() 内部使用 Task 调用异步函数。
@MainActor @Observable class ContentViewModel {
private(set) var result: Weather?
func load() async {
// Mimic 1 second network delay.
try? await Task.sleep(nanoseconds: 1_000_000_000)
self.result = .sunny
}
}
接下来使用 @State 定义 view model,由视图调用 load():
struct ContentView: View {
@State var viewModel = ContentViewModel()
var body: some View {
Text(viewModel.result?.rawValue ?? "Loading...")
.task {
await viewModel.load()
}
}
}
在 Dart 中,默认所有工作在主 isolate 上运行。要在 Dart 中实现相同示例,首先创建 Weather enum:
enum Weather { rainy, windy, sunny }
然后定义简单的 view model(类似 SwiftUI 中的做法)以获取天气。在 Dart 中,Future 对象表示将来提供的值,与 Swift 的 @Observable
类似。本例中 view model 内的函数返回 Future<Weather>:
@immutable
class HomePageViewModel {
const HomePageViewModel();
Future<Weather> load() async {
await Future.delayed(const Duration(seconds: 1));
return Weather.sunny;
}
}
本例中的 load() 与 Swift 代码类似。Dart 函数标记为 async 是因为使用了 await。
此外,标记为 async 的 Dart 函数会自动返回 Future,即在 async 函数内无需手动创建 Future
实例。
最后一步是显示天气值。在 Flutter 中,FutureBuilder
和 StreamBuilder
widget 用于在 UI 中显示 Future 的结果。以下示例使用 FutureBuilder:
class HomePage extends StatelessWidget {
const HomePage({super.key});
final HomePageViewModel viewModel = const HomePageViewModel();
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
// Feed a FutureBuilder to your widget tree.
child: FutureBuilder<Weather>(
// Specify the Future that you want to track.
future: viewModel.load(),
builder: (context, snapshot) {
// A snapshot is of type `AsyncSnapshot` and contains the
// state of the Future. By looking if the snapshot contains
// an error or if the data is null, you can decide what to
// show to the user.
if (snapshot.hasData) {
return Center(child: Text(snapshot.data.toString()));
} else {
return const Center(child: CupertinoActivityIndicator());
}
},
),
);
}
}
完整示例请参阅 GitHub 上的 async_weather 文件。
利用后台线程 / isolate
#Flutter 应用可在多种多核硬件上运行,包括 macOS 和 iOS 设备。为提升性能,有时必须在不同核心上并发运行任务,这对避免长时间操作阻塞 UI 渲染尤为重要。
在 Swift 中,可利用 GCD 在不同服务质量(qos)的全局队列上运行任务,以表示任务优先级。
func parse(string: String, completion: @escaping ([String:Any]) -> Void) {
// Mimic 1 sec delay.
DispatchQueue(label: "data_processing_queue", qos: .userInitiated)
.asyncAfter(deadline: .now() + 1) {
let result: [String:Any] = ["foo": 123]
completion(result)
}
}
}
在 Dart 中,可将计算卸载到 worker isolate(常称为后台 worker)。常见场景是 spawn 一个简单的 worker isolate,在 worker 退出时通过消息返回结果。可使用
Isolate.run() spawn isolate 并运行计算:
void main() async {
// Read some data.
final jsonData = await Isolate.run(() => jsonDecode(jsonString) as Map<String, dynamic>);`
// Use that data.
print('Number of JSON keys: ${jsonData.length}');
}
在 Flutter 中,也可使用 compute 函数启动 isolate 运行回调:
final jsonData = await compute(getNumberOfKeys, jsonString);
此时回调为如下所示的顶层函数:
Map<String, dynamic> getNumberOfKeys(String jsonString) {
return jsonDecode(jsonString);
}
有关 Dart 的更多信息请参阅 Learning Dart as a Swift developer,有关 Flutter 请参阅 Flutter for SwiftUI developers 或 Flutter for UIKit developers。
除非另有说明,本文档之所提及适用于 Flutter 3.44.0 版本。本页面最后更新时间:2026-06-04。查看文档源码 或者 为本页面内容提出建议。