【问题标题】:Why network requests in Flutter doesn't block the UI为什么 Flutter 中的网络请求不会阻塞 UI
【发布时间】:2020-01-29 08:38:09
【问题描述】:

我知道 Dart 是单线程的,flutter 也是,所以如果我做一些繁重的任务,它会阻塞 UI 事件队列,但是网络请求需要几秒钟而不阻塞 UI。

那么,为什么 Socket 不会阻塞 UI?困扰我的是为什么socket不会阻塞UI,但是繁重的任务却会,虽然都是异步任务。

例如,这段代码会阻塞 UI

@override
void initState() {
super.initState();
Future((){
  var result;
  for (var i = 0; i < 1000000; ++i) {
    result = 'result is $i';
  }
  print(result);
});

这段代码是正常的HTTP请求,不会阻塞UI

get() async {
  var httpClient = new HttpClient();
  var uri = new Uri.http(
      'example.com', '/path1/path2', {'param1': '42', 'param2': 'foo'});
  var request = await httpClient.getUrl(uri);
  var response = await request.close();
  var responseBody = await response.transform(UTF8.decoder).join();
}

socket不阻塞UI的原因是把请求过程拆分成多个部分?并将这些部分发送到当前的微任务队列中,正如这个答案所说:

https://stackoverflow.com/a/56783713/6540631

那么,有人知道套接字是如何异步实现的吗? socket是使用Isolate、Future还是其他方式?socket运行在UI线程还是其他线程?

而且,如果我必须执行在 UI 线程中无法拆分的繁重任务(例如文本布局),我该怎么办?


补充说明:

我知道如何使用 Future 和 Isolate,但是我遇到了问题。

如果在隔离中使用 TextPainter.layout 将得到一个本地编译器错误 找不到函数。

我需要排版很多字,而且需要很长时间 (100ms+),它会阻塞 UI 线程。

我该怎么办?

https://github.com/flutter/flutter/issues/30604

UI 包的 Flutter 引擎原生 API 仅可用 在初级隔离中。

https://github.com/flutter/flutter/issues/30604#issuecomment-481380706

现在您必须编写自己的换行逻辑 - 也许作为一个插件。我们目前没有任何用于处理文本的 API 在单独的隔离中布局。 @GaryQian 可能有其他想法 关于这个。

https://github.com/flutter/flutter/issues/30604#issuecomment-526013977

所以我必须在UI线程中进行文本布局(使用TextPainter),虽然写一个插件可以解决这个问题并且效果很好,有没有更简单的方法?

我想我可以从socket的实现细节中得到帮助,所以我提出了这个问题。

【问题讨论】:

  • 我既不知道flutter也不知道dart,但我相信文档很好地解释了异步任务的概念:dart.dev/codelabs/async-await#uncompleted
  • 1.单线程并不意味着一切都是阻塞的。工作仍然可以异步完成(您可能想阅读coroutines)。 2. Dart 中的每个isolate 都是单线程的,但Dart 支持多个isolate。 3. Flutter 有一个 UI 隔离,但 Flutter engine 使用多个线程来处理各种事情。
  • @Kaenbyou Rin 但是为什么繁重的任务会阻塞UI,网络请求却没有,虽然他们都使用异步任务
  • @jamesdlin 套接字是否使用隔离?困扰我的是为什么socket不会阻塞UI,但是繁重的任务却会,虽然都是异步任务
  • @LuckyDog 套接字是否使用 Isolate 是实现细节。它可能已经启动了一个线程并等待同步 I/O 请求,或者它可能使用了系统本机异步 I/O API(Windows 上的 IOCP 或 linux 上的 epoll)。

标签: flutter dart


【解决方案1】:

在 dart 中,网络调用本质上是 asnycronous,并返回 Future。当任何东西是asynchronous 时,它会在后台运行并在任务完成时返回结果或响应。它与 javascript 中的 Promise 非常相似。以下是来自Official Docs 的 dart 中与 Async 相关的关键术语列表。

关键术语:


同步操作:同步操作会阻止其他操作执行,直到它完成。
同步函数:同步函数只执行同步操作。
异步操作:异步操作一旦启动,就允许其他操作在完成之前执行。
异步函数:异步函数至少执行一个异步操作,也可以执行同步操作。

在您的情况下,您使用了Future,但函数必须通过await 产生以允许在隔离中执行其他操作。如果你不让步,它会阻塞 UI 线程。这正是你在第一个代码块中得到的,并且 UI 被阻塞了。您已经使用了Future,但计算仍然是同步的。这里有一个精确的Post 供更多参考。

【讨论】:

  • 为什么socket不阻塞UI?这就是我感到困惑的地方。
  • 套接字也是一个网络,这就是它被隔离的原因。如果您仍然对它感到困惑,请参阅您正在使用的套接字库的文档并发表评论。
  • 但是在Android(4.0之前),Socket会阻塞UI。所以我猜Socket不是隔离的,但是Flutter系统隔离了socket。
猜你喜欢
  • 1970-01-01
  • 2021-08-29
  • 1970-01-01
  • 2012-04-15
  • 2019-11-09
  • 2020-10-30
  • 1970-01-01
  • 2016-06-26
相关资源
最近更新 更多