Dart 未来阻塞主线程
Dart future blocking main thread
我正在开发一款捕捉和处理图像的应用程序。代码的简化版本是:
build() {
return FloatingActionButton(
onPressed: processImage,
child: Icon(
Icons.camera_alt,
color: color,
),
);
}
processImage(Camera image) async {
await image.process();
}
在另一个 class:
Future<image> process() {
return Future(() {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
//process image
}
}
});
}
但是当 process()
为 运行 时,UI 冻结。
为什么会这样?那个函数不是在后台传递给 Future 构造函数 运行 吗?
您可以将间隙插入到事件循环中。
简单方法:
Future<image> process2() {
return Future(() async {
for (var x = 0; x < width; x++) {
for (var y = 0; y < height; y++) {
// process
}
if (x % 100 == 0) {
await Future.delayed(Duration(seconds: 100));
}
}
});
}
由于 Dart 使用事件循环,所有代码(同步和异步)都将简单地 运行 在同一个 isolate
上(想想其他语言中的 thread
作为类比),只是在不同的时间点。因此,当您的 process
方法出列并执行时,它会阻塞线程并导致帧由于较长的执行时间而被丢弃,尽管它是异步的。该问题的最佳解决方案是在新线程中生成另一个 isolate,并在那里进行计算。 Flutter 为这个确切的用例提供了一个方便的方法,称为 compute
。它需要一个 top-level 函数(不在 class 中,也不是匿名函数),它可以有一个基本类型参数(包括 Map
和 List
)作为参数,并且将 return 在未来的某个时候。有关 compute
的更多信息,请参阅上面链接的文档。
如果您有多个参数需要传递给 compute
,一个常见的模式(在这个用例之外)是制作一个将 class' 字段序列化为 Map<String, dynamic>
,以及一个从 Map<String, dynamic>
创建对象的工厂构造函数。这个过程使用反射会更容易,但由于性能原因,Flutter 禁用了它。
有关 Flutter 文档中 compute
的完整示例,请参阅此处:https://flutter.dev/docs/cookbook/networking/background-parsing
我正在开发一款捕捉和处理图像的应用程序。代码的简化版本是:
build() {
return FloatingActionButton(
onPressed: processImage,
child: Icon(
Icons.camera_alt,
color: color,
),
);
}
processImage(Camera image) async {
await image.process();
}
在另一个 class:
Future<image> process() {
return Future(() {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
//process image
}
}
});
}
但是当 process()
为 运行 时,UI 冻结。
为什么会这样?那个函数不是在后台传递给 Future 构造函数 运行 吗?
您可以将间隙插入到事件循环中。
简单方法:
Future<image> process2() {
return Future(() async {
for (var x = 0; x < width; x++) {
for (var y = 0; y < height; y++) {
// process
}
if (x % 100 == 0) {
await Future.delayed(Duration(seconds: 100));
}
}
});
}
由于 Dart 使用事件循环,所有代码(同步和异步)都将简单地 运行 在同一个 isolate
上(想想其他语言中的 thread
作为类比),只是在不同的时间点。因此,当您的 process
方法出列并执行时,它会阻塞线程并导致帧由于较长的执行时间而被丢弃,尽管它是异步的。该问题的最佳解决方案是在新线程中生成另一个 isolate,并在那里进行计算。 Flutter 为这个确切的用例提供了一个方便的方法,称为 compute
。它需要一个 top-level 函数(不在 class 中,也不是匿名函数),它可以有一个基本类型参数(包括 Map
和 List
)作为参数,并且将 return 在未来的某个时候。有关 compute
的更多信息,请参阅上面链接的文档。
如果您有多个参数需要传递给 compute
,一个常见的模式(在这个用例之外)是制作一个将 class' 字段序列化为 Map<String, dynamic>
,以及一个从 Map<String, dynamic>
创建对象的工厂构造函数。这个过程使用反射会更容易,但由于性能原因,Flutter 禁用了它。
有关 Flutter 文档中 compute
的完整示例,请参阅此处:https://flutter.dev/docs/cookbook/networking/background-parsing