多个分离株与一个分离株

7ma*_*ada 14 dart dart-isolates flutter

隔离如何分布在 CPU 核心上

在 Dart 中,您可以同时运行多个隔离,但我尚未找到使用隔离的指南或最佳实践。

我的问题是,同时运行的isolate 数量会如何影响整体CPU 使用率和性能,以及使用少量isolate(甚至仅一个)是否更好。

Max*_*lin 17

每一个线程一个隔离

\n

一个隔离占用一个平台线程 -在调试具有多个隔离的 Dart/Flutter 应用程序时,您可以在VSCode“调用堆栈”窗格中观察每个隔离创建的线程。如果感兴趣的工作负载允许并行性,您可以通过隔离获得巨大的性能提升。

\n

请注意,Dart 显式抽象了实现细节,并且文档避免了隔离及其内在的调度细节。

\n

隔离数 = \xc2\xb1 CPU 核心数

\n

根据经验确定隔离/线程的数量时,您可以将核心数量作为初始值。您可以import \'dart:io\';使用该Platform.numberOfProcessors属性来确定核心数量。不过,需要进行微调实验来看看哪个数字更有意义。有很多因素会影响最佳线程数:

\n
    \n
  1. CPU 中存在同步多线程 (SMT),例如 Intel 超线程
  2. \n
  3. 指令级并行性 (ILP) 和为您的代码生成的特定机器代码
  4. \n
  5. CPU架构
  6. \n
  7. 移动/智能手机场景与桌面 - 例如,英特尔 CPU 具有相同的内核,节流倾向较小。智能手机具有高效和高性能的核心,它们很容易慢跑,创建无数的线程可能会导致更糟糕的结果,因为操作系统会减慢代码速度。
  8. \n
\n

例如,对于我的一个 Flutter 应用程序,它使用多个隔离区来并行化文件处理,我根据经验得出以下代码段,用于确定要创建的隔离区的数量:

\n
var numberOfIsolates = max(Platform.numberOfProcessors - 2, 2)\n
Run Code Online (Sandbox Code Playgroud)\n

隔离不是线程

\n

isolate 提供的模型比标准线程模型建议的限制要严格得多。

\n

隔离不共享内存 线程可以读取彼此的变量。存在技术例外,例如,由于 Flutter 2.5.0 隔离使用一个堆,因此存在跨隔离共享的不可变类型的例外,例如字符串 - 尽管它们是实现细节并且不会改变概念。

\n

Isolates communicate only via messages 线程中的大量同步原语(临界区、锁、信号量、互斥体等)相比。

\n

明显的权衡是,隔离不容易出现多线程编程问题(棘手的错误、调试、开发复杂性),但提供的并行性实现功能较少。

\n

在 Dart/Flutter 中,只有 2 种方法可以使用 Isolates:

\n
    \n
  1. 低级别、Dart 风格 - 使用 Isolate 类生成单独的隔离区、设置用于消息传递的发送/接收端口、代码入口点。
  2. \n
  3. 更高层次Compute辅助函数 - 它获取输入参数,创建具有定义入口点的新隔离,处理输入并提供单个结果 - 不是来回通信、事件流等、请求响应模式。
  4. \n
\n

请注意,在 Dart/Flutter SDK 中,没有并行 API,例如 .NET 中的任务并行库 (TPL),它提供了多核 CPU 优化的 API 来在多个线程上处理数据,例如并行对集合进行排序。大量算法可以从使用线程的并行性中受益,但对于没有共享内存的隔离模型来说是不可行的。此外,没有隔离池,一组隔离启动并运行并等待传入​​任务(我必须自己创建一个https://pub.dev/packages/isolate_pool_2)。

\n

PS: SMT、ILP等对多线程性能的影响可以通过以下CPU基准测试来观察(https://play.google.com/store/apps/details?id=xcom.saplin.xOPS) - 例如,人们可以看到,就进行计算的多个多线程而言,通常存在最佳点。它大于核心数。例如,在我的具有 6 个内核和每个 CPU 12 个线程的英特尔 i7 第八代 MacBook 上,当线程数约为内核数的 4 倍时,观察到最佳性能。

\n