多个 Isolate 与一个 Isolate
Multiple Isolates vs one Isolate
隔离物如何分布在 CPU 个核心上
在 Dart 中,您可以同时 运行 多个 isolate,但我一直无法找到使用 isolate 的指南或最佳实践。
我的问题是总体 CPU 使用率和性能如何受同时 运行 隔离物数量的影响,使用少量隔离物(或甚至只有一个)或没有。
跨 CPU 个核心的隔离分布由 OS 完成。但是每个isolate对应一个thread。要使用的 isolate 数量将取决于 CPU 物理可用内核的数量。
这里有一篇简短的文章对此进行了说明:
https://martin-robert-fink.medium.com/dart-is-indeed-multi-threaded-94e75f66aa1e
每个线程一个隔离
一个隔离占用一个平台线程 - 您可以在 VSCode[=65= 的 调用堆栈 窗格中观察每个隔离创建的线程] 在调试具有多个隔离的 Dart/Flutter 应用程序时。如果感兴趣的工作负载允许并行性,您可以通过隔离获得巨大的性能提升。
请注意,Dart 明确抽象了实现细节,文档避免了 isolate 调度及其内在函数的细节。
分离株数 = ±CPU 核心数
在确定isolates/threads的数量时,根据经验可以将核心数作为初始值。您可以 import 'dart:io';
并使用 Platform.numberOfProcessors
属性 来确定核心数。尽管需要微调实验才能确定哪个数字更有意义。影响最佳线程数的因素有很多:
- CPU 中存在同步多线程 (SMT),例如英特尔超线程
- 指令级并行性 (ILP) 和为您的代码生成的特定机器代码
- CPU 架构
- Mobile/smartphone 场景与桌面 - 例如Intel CPU 具有相同的内核,节流倾向较小。智能手机具有效率和 high-performance 内核,它们很容易运行,创建大量线程会导致更糟糕的结果,因为 OS 会减慢您的代码速度。
例如对于我的一个使用多个 isolate 来并行处理文件的 Flutter 应用程序,我根据经验得出以下代码段,确定要创建的 isolates 的数量:
var numberOfIsolates = max(Platform.numberOfProcessors - 2, 2)
隔离不是线程
isolate 提供的模型比标准线程模型所建议的模型更具限制性。
Isolates 不共享内存 vs 线程可以读取彼此的变量。有技术例外,例如由于 Flutter 2.5.0 isolates 使用一个堆,因此跨 isolates 共享的不可变类型存在例外情况,例如字符串 - 尽管它们是一个实现细节并且不会改变概念。
Isolates communicate only via messages
vs 线程中的许多同步 prymitives(关键部分、锁、信号量、互斥量等)。
明显的权衡是 Isolates 不易 multi-threaded 编程恐怖(棘手的错误、调试、开发复杂性)但提供较少的实现并行性的能力。
在 Dart/Flutter 中,只有两种方法可以使用 Isolates:
- 低级别,Dart 风格 - 使用 Isolate class 生成单独的隔离,set-up send/receive 用于消息传递的端口,代码入口点。
- Flutter 中更高级别的
Compute
辅助函数 - 它获取输入参数,创建具有定义入口点的新隔离,处理输入并提供单个结果 - 不是来回通信、事件流等., request-response 模式.
请注意,在 Dart/Flutter SDK 中没有并行 API,例如 .NET 中的任务并行库 (TPL),它提供 multi-core CPU 优化的 API 来处理多线程上的数据,例如并行排序集合。大量算法可以从使用线程的并行性中受益,但对于没有共享内存的 Isolates 模型是不可行的。也没有隔离池,一组隔离 运行 并等待传入的任务(我必须自己创建一个 https://github.com/maxim-saplin/ikvpack/blob/main/lib/src/isolate_helpers.dart)。
P.S.:SMT、ILP等对多胎性能的影响可以通过以下CPUbenchmark( https://play.google.com/store/apps/details?id=xcom.saplin.xOPS) - 例如人们可以看到,就执行计算的多个线程而言,通常有一个最佳点。它大于核心数。例如。在我的 Intel i7 第 8 代 MacBook 上,每个 CPU 有 6 个内核和 12 个线程,观察到最佳性能时线程数大约是内核数的 4 倍。
隔离物如何分布在 CPU 个核心上
在 Dart 中,您可以同时 运行 多个 isolate,但我一直无法找到使用 isolate 的指南或最佳实践。
我的问题是总体 CPU 使用率和性能如何受同时 运行 隔离物数量的影响,使用少量隔离物(或甚至只有一个)或没有。
跨 CPU 个核心的隔离分布由 OS 完成。但是每个isolate对应一个thread。要使用的 isolate 数量将取决于 CPU 物理可用内核的数量。
这里有一篇简短的文章对此进行了说明: https://martin-robert-fink.medium.com/dart-is-indeed-multi-threaded-94e75f66aa1e
每个线程一个隔离
一个隔离占用一个平台线程 - 您可以在 VSCode[=65= 的 调用堆栈 窗格中观察每个隔离创建的线程] 在调试具有多个隔离的 Dart/Flutter 应用程序时。如果感兴趣的工作负载允许并行性,您可以通过隔离获得巨大的性能提升。
请注意,Dart 明确抽象了实现细节,文档避免了 isolate 调度及其内在函数的细节。
分离株数 = ±CPU 核心数
在确定isolates/threads的数量时,根据经验可以将核心数作为初始值。您可以 import 'dart:io';
并使用 Platform.numberOfProcessors
属性 来确定核心数。尽管需要微调实验才能确定哪个数字更有意义。影响最佳线程数的因素有很多:
- CPU 中存在同步多线程 (SMT),例如英特尔超线程
- 指令级并行性 (ILP) 和为您的代码生成的特定机器代码
- CPU 架构
- Mobile/smartphone 场景与桌面 - 例如Intel CPU 具有相同的内核,节流倾向较小。智能手机具有效率和 high-performance 内核,它们很容易运行,创建大量线程会导致更糟糕的结果,因为 OS 会减慢您的代码速度。
例如对于我的一个使用多个 isolate 来并行处理文件的 Flutter 应用程序,我根据经验得出以下代码段,确定要创建的 isolates 的数量:
var numberOfIsolates = max(Platform.numberOfProcessors - 2, 2)
隔离不是线程
isolate 提供的模型比标准线程模型所建议的模型更具限制性。
Isolates 不共享内存 vs 线程可以读取彼此的变量。有技术例外,例如由于 Flutter 2.5.0 isolates 使用一个堆,因此跨 isolates 共享的不可变类型存在例外情况,例如字符串 - 尽管它们是一个实现细节并且不会改变概念。
Isolates communicate only via messages
vs 线程中的许多同步 prymitives(关键部分、锁、信号量、互斥量等)。
明显的权衡是 Isolates 不易 multi-threaded 编程恐怖(棘手的错误、调试、开发复杂性)但提供较少的实现并行性的能力。
在 Dart/Flutter 中,只有两种方法可以使用 Isolates:
- 低级别,Dart 风格 - 使用 Isolate class 生成单独的隔离,set-up send/receive 用于消息传递的端口,代码入口点。
- Flutter 中更高级别的
Compute
辅助函数 - 它获取输入参数,创建具有定义入口点的新隔离,处理输入并提供单个结果 - 不是来回通信、事件流等., request-response 模式.
请注意,在 Dart/Flutter SDK 中没有并行 API,例如 .NET 中的任务并行库 (TPL),它提供 multi-core CPU 优化的 API 来处理多线程上的数据,例如并行排序集合。大量算法可以从使用线程的并行性中受益,但对于没有共享内存的 Isolates 模型是不可行的。也没有隔离池,一组隔离 运行 并等待传入的任务(我必须自己创建一个 https://github.com/maxim-saplin/ikvpack/blob/main/lib/src/isolate_helpers.dart)。
P.S.:SMT、ILP等对多胎性能的影响可以通过以下CPUbenchmark( https://play.google.com/store/apps/details?id=xcom.saplin.xOPS) - 例如人们可以看到,就执行计算的多个线程而言,通常有一个最佳点。它大于核心数。例如。在我的 Intel i7 第 8 代 MacBook 上,每个 CPU 有 6 个内核和 12 个线程,观察到最佳性能时线程数大约是内核数的 4 倍。