flutter-handling-concurrency
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseManaging Dart Concurrency and Isolates
管理Dart并发与Isolate
Contents
目录
Core Concepts
核心概念
Dart utilizes a single-threaded execution model driven by an Event Loop (comparable to the iOS main loop). By default, all Flutter application code runs on the Main Isolate.
- Asynchronous Operations (/
async): Use for non-blocking I/O tasks (network requests, file access). The Event Loop continues processing other events while waiting for theawaitto complete.Future - Isolates: Dart's implementation of lightweight threads. Isolates possess their own isolated memory and do not share state. They communicate exclusively via message passing.
- Main Isolate: The default thread where UI rendering and event handling occur. Blocking this isolate causes UI freezing (jank).
- Worker Isolate: A spawned isolate used to offload CPU-bound tasks (e.g., decoding large JSON blobs) to prevent Main Isolate blockage.
Dart采用由事件循环(Event Loop)驱动的单线程执行模型(类似于iOS主循环)。默认情况下,所有Flutter应用代码都运行在Main Isolate上。
- 异步操作(/
async): 用于非阻塞I/O任务(网络请求、文件访问)。在等待await完成期间,事件循环会继续处理其他事件。Future - Isolate: Dart实现的轻量级线程。Isolate拥有独立的隔离内存,不共享状态,仅通过消息传递进行通信。
- Main Isolate: 默认线程,负责UI渲染和事件处理。阻塞该Isolate会导致UI卡顿(jank)。
- Worker Isolate: 生成的隔离线程,用于卸载CPU密集型任务(例如解码大型JSON数据),以避免阻塞Main Isolate。
Decision Matrix: Async vs. Isolates
决策矩阵:Async 与 Isolate对比
Apply the following conditional logic to determine the correct concurrency approach:
- If the task is I/O bound (e.g., HTTP request, database read) -> Use /
asyncon the Main Isolate.await - If the task is CPU-bound but executes quickly (< 16ms) -> Use /
asyncon the Main Isolate.await - If the task is CPU-bound, takes significant time, and runs once (e.g., parsing a massive JSON payload) -> Use .
Isolate.run() - If the task requires continuous or repeated background processing with multiple messages passed over time -> Use with
Isolate.spawn()andReceivePort.SendPort
应用以下条件逻辑来选择正确的并发方案:
- 如果任务是I/O密集型(例如HTTP请求、数据库读取)-> 在Main Isolate上使用/
async。await - 如果任务是CPU密集型但执行速度快(<16ms)-> 在Main Isolate上使用/
async。await - 如果任务是CPU密集型、耗时较长且仅执行一次(例如解析超大JSON负载)-> 使用。
Isolate.run() - 如果任务需要持续或重复的后台处理,且随时间需要传递多条消息-> 结合与
Isolate.spawn()、ReceivePort使用。SendPort
Workflows
工作流程
Implementing Standard Asynchronous UI
实现标准异步UI
Use this workflow to fetch and display non-blocking asynchronous data.
Task Progress:
- Mark the data-fetching function with the keyword.
async - Return a from the function.
Future<T> - Use the keyword to yield execution until the operation completes.
await - Wrap the UI component in a (or
FutureBuilder<T>for streams).StreamBuilder - Handle ,
ConnectionState.waiting, andhasErrorstates within the builder.hasData - Run validator -> review UI for loading indicators -> fix missing states.
使用此工作流程来获取并显示非阻塞异步数据。
任务步骤:
- 为数据获取函数标记关键字。
async - 函数返回类型。
Future<T> - 使用关键字暂停执行,直到操作完成。
await - 将UI组件包裹在中(如果是流则使用
FutureBuilder<T>)。StreamBuilder - 在builder中处理、
ConnectionState.waiting和hasError状态。hasData - 运行验证器 -> 检查UI中的加载指示器 -> 修复缺失的状态处理。
Offloading Short-Lived Heavy Computation
卸载短期密集型计算任务
Use this workflow for one-off, CPU-intensive tasks using Dart 2.19+.
Task Progress:
- Identify the CPU-bound operation blocking the Main Isolate.
- Extract the computation into a standalone callback function.
- Ensure the callback function signature accepts exactly one required, unnamed argument (as per specific architectural constraints).
- Invoke passing the callback.
Isolate.run() - the result of
awaitin the Main Isolate.Isolate.run() - Assign the returned value to the application state.
针对Dart 2.19+版本,使用此工作流程处理一次性CPU密集型任务。
任务步骤:
- 识别阻塞Main Isolate的CPU密集型操作。
- 将计算逻辑提取为独立的回调函数。
- 确保回调函数签名仅接受一个必填的未命名参数(符合特定架构约束)。
- 调用并传入该回调函数。
Isolate.run() - 在Main Isolate中
await的结果。Isolate.run() - 将返回值赋值给应用状态。
Establishing Long-Lived Worker Isolates
创建长期运行的Worker Isolate
Use this workflow for persistent background processes requiring continuous bidirectional communication.
Task Progress:
- Instantiate a on the Main Isolate to listen for messages.
ReceivePort - Spawn the worker isolate using , passing the
Isolate.spawn()as the initial message.ReceivePort.sendPort - In the worker isolate, instantiate its own .
ReceivePort - Send the worker's back to the Main Isolate via the initial port.
SendPort - Store the worker's in the Main Isolate for future message dispatching.
SendPort - Implement listeners on both instances to handle incoming messages.
ReceivePort - Run validator -> review memory leaks -> ensure ports are closed when the isolate is no longer needed.
使用此工作流程处理需要持续双向通信的持久化后台进程。
任务步骤:
- 在Main Isolate上实例化以监听消息。
ReceivePort - 使用生成worker isolate,将
Isolate.spawn()作为初始消息传递。ReceivePort.sendPort - 在worker isolate中实例化自己的。
ReceivePort - 通过初始端口将worker的发送回Main Isolate。
SendPort - 在Main Isolate中存储worker的,以便未来发送消息。
SendPort - 在两个实例上实现监听器,处理传入的消息。
ReceivePort - 运行验证器 -> 检查内存泄漏 -> 确保在isolate不再需要时关闭端口。
Examples
示例
Example 1: Asynchronous UI with FutureBuilder
示例1:使用FutureBuilder实现异步UI
dart
// 1. Define the async operation
Future<String> fetchUserData() async {
await Future.delayed(const Duration(seconds: 2)); // Simulate network I/O
return "User Data Loaded";
}
// 2. Consume in the UI
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: fetchUserData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('Result: ${snapshot.data}');
}
},
);
}dart
// 1. Define the async operation
Future<String> fetchUserData() async {
await Future.delayed(const Duration(seconds: 2)); // Simulate network I/O
return "User Data Loaded";
}
// 2. Consume in the UI
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: fetchUserData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('Result: ${snapshot.data}');
}
},
);
}Example 2: Short-Lived Isolate (Isolate.run
)
Isolate.run示例2:短期运行Isolate(Isolate.run
)
Isolate.rundart
import 'dart:isolate';
import 'dart:convert';
// 1. Define the heavy computation callback
// Note: Adhering to the strict single-argument signature requirement.
List<dynamic> decodeHeavyJson(String jsonString) {
return jsonDecode(jsonString) as List<dynamic>;
}
// 2. Offload to a worker isolate
Future<List<dynamic>> processDataInBackground(String rawJson) async {
// Isolate.run spawns the isolate, runs the computation, returns the value, and exits.
final result = await Isolate.run(() => decodeHeavyJson(rawJson));
return result;
}dart
import 'dart:isolate';
import 'dart:convert';
// 1. Define the heavy computation callback
// Note: Adhering to the strict single-argument signature requirement.
List<dynamic> decodeHeavyJson(String jsonString) {
return jsonDecode(jsonString) as List<dynamic>;
}
// 2. Offload to a worker isolate
Future<List<dynamic>> processDataInBackground(String rawJson) async {
// Isolate.run spawns the isolate, runs the computation, returns the value, and exits.
final result = await Isolate.run(() => decodeHeavyJson(rawJson));
return result;
}Example 3: Long-Lived Isolate (ReceivePort
/ SendPort
)
ReceivePortSendPort示例3:长期运行Isolate(ReceivePort
/ SendPort
)
ReceivePortSendPortdart
import 'dart:isolate';
class WorkerManager {
late SendPort _workerSendPort;
final ReceivePort _mainReceivePort = ReceivePort();
Isolate? _isolate;
Future<void> initialize() async {
// 1. Spawn isolate and pass the Main Isolate's SendPort
_isolate = await Isolate.spawn(_workerEntry, _mainReceivePort.sendPort);
// 2. Listen for messages from the Worker Isolate
_mainReceivePort.listen((message) {
if (message is SendPort) {
// First message is the Worker's SendPort
_workerSendPort = message;
_startCommunication();
} else {
// Subsequent messages are data payloads
print('Main Isolate received: $message');
}
});
}
void _startCommunication() {
// Send data to the worker
_workerSendPort.send("Process this data");
}
// 3. Worker Isolate Entry Point
static void _workerEntry(SendPort mainSendPort) {
final workerReceivePort = ReceivePort();
// Send the Worker's SendPort back to the Main Isolate
mainSendPort.send(workerReceivePort.sendPort);
// Listen for incoming tasks
workerReceivePort.listen((message) {
print('Worker Isolate received: $message');
// Perform work and send result back
final result = "Processed: $message";
mainSendPort.send(result);
});
}
void dispose() {
_mainReceivePort.close();
_isolate?.kill();
}
}dart
import 'dart:isolate';
class WorkerManager {
late SendPort _workerSendPort;
final ReceivePort _mainReceivePort = ReceivePort();
Isolate? _isolate;
Future<void> initialize() async {
// 1. Spawn isolate and pass the Main Isolate's SendPort
_isolate = await Isolate.spawn(_workerEntry, _mainReceivePort.sendPort);
// 2. Listen for messages from the Worker Isolate
_mainReceivePort.listen((message) {
if (message is SendPort) {
// First message is the Worker's SendPort
_workerSendPort = message;
_startCommunication();
} else {
// Subsequent messages are data payloads
print('Main Isolate received: $message');
}
});
}
void _startCommunication() {
// Send data to the worker
_workerSendPort.send("Process this data");
}
// 3. Worker Isolate Entry Point
static void _workerEntry(SendPort mainSendPort) {
final workerReceivePort = ReceivePort();
// Send the Worker's SendPort back to the Main Isolate
mainSendPort.send(workerReceivePort.sendPort);
// Listen for incoming tasks
workerReceivePort.listen((message) {
print('Worker Isolate received: $message');
// Perform work and send result back
final result = "Processed: $message";
mainSendPort.send(result);
});
}
void dispose() {
_mainReceivePort.close();
_isolate?.kill();
}
}