【问题标题】:Dart future blocking main threadDart 未来阻塞主线程
【发布时间】:2020-10-25 03:17:32
【问题描述】:

我正在开发一个捕获和处理图像的应用程序。代码的简化版本是:

build() {
   return FloatingActionButton(
        onPressed: processImage,
        child: Icon(
          Icons.camera_alt,
          color: color,
        ),
      ); 
}

processImage(Camera image) async {
   await image.process();   
}

在另一个班级:

Future<image> process() {
  return Future(() {
    for (int x = 0; x < width; x++) {
      for (int y = 0; y < height; y++) {
        //process image
      }
    }
  });
}

但是当process() 运行时,UI 会冻结。

为什么会这样?传递给Future构造函数的那个​​函数不是在后台运行吗?

【问题讨论】:

  • 我不是 100% 确定,但我知道 dart 使用事件循环并且一切都将在主线程上运行(可能在将来的某个时间点,在异步代码的情况下) .因此,该代码最终将在主线程上执行,从而导致阻塞。考虑使用 Dart 的分离器;那应该可以解决问题。 Flutter 有一个内置的便捷方法可以为您执行此操作,但我不记得它叫什么。
  • @GregoryConrad 谢谢,这对我有用,不是一个非常优雅的解决方案,但它有效,如果你想把它作为一个答案,我很乐意把它作为正确的答案
  • compute()函数中什么不是“优雅”?
  • @pskink 我的函数接收6个参数,你不能调用一个类方法:"The callback argument must be a top-level function, not a closure or an instance or static method of a class",你只能传递一个参数,所以我不得不把我所有的参数都转换成一个Map&lt;String, dynamic&gt;,创建一个接收映射的顶级函数,并解构为原始变量。

标签: flutter dart future


【解决方案1】:

由于 Dart 使用事件循环,所有代码(同步和异步)将简单地在相同的 isolate 上运行(将其他语言中的 thread 视为类比),只是在不同的时间点。因此,当您的 process 方法出列并执行时,尽管是异步的,但由于执行时间较长,它将阻塞线程并导致帧被丢弃。该问题的最佳解决方案是在新线程中生成另一个隔离,并在那里执行计算。 Flutter 为这个确切的用例提供了一种方便的方法,称为compute。它需要一个顶级函数(不在类中,也不是匿名的),该函数可以有一个原始类型参数(包括MapList)作为参数,并将在将来的某个时间返回。有关compute 的更多信息,请参阅上面链接的文档。

如果您有多个参数需要传递给compute,一个常见的模式(除了这个用例之外)是创建一个将类的字段序列化为Map&lt;String, dynamic&gt; 的方法,以及一个工厂构造函数从Map&lt;String, dynamic&gt; 创建一个对象。这个过程使用反射会更容易,但由于性能原因,Flutter 禁用了它。

有关 Flutter 文档中有关 compute 的完整示例,请参见此处:https://flutter.dev/docs/cookbook/networking/background-parsing

【讨论】:

    【解决方案2】:

    您可以在事件循环中插入间隙。
    简单的方法:

    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));
          }
        }
      });
    }
    
    

    【讨论】:

    • 错误答案,这无济于事。 UI 仍然冻结。
    猜你喜欢
    • 2018-02-16
    • 1970-01-01
    • 2015-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多