跳到主要内容

TaskPool和Worker的对比 (TaskPool和Worker)

TaskPool和Worker的作用是为应用程序提供多线程运行环境,用于处理耗时计算任务或其他密集型任务,避免任务阻塞宿主线程,提高系统性能和资源利用率。

本文将从实现特点适用场景两个方面比较TaskPool与Worker。

实现特点对比

表1 TaskPool和Worker的实现特点对比

实现TaskPoolWorker
内存模型线程间隔离,内存不共享。线程间隔离,内存不共享。
参数传递机制采用标准的结构化克隆算法(Structured Clone)进行序列化、反序列化,完成参数传递。 支持ArrayBuffer转移、SharedArrayBuffer共享和Sendable引用传递。采用标准的结构化克隆算法(Structured Clone)进行序列化、反序列化,完成参数传递。 支持ArrayBuffer转移、SharedArrayBuffer共享和Sendable引用传递。
参数传递直接传递,无需封装。消息对象唯一参数,需要自己封装。
方法调用直接传入并调用@Concurrent修饰的方法。在Worker线程中解析消息并调用对应方法。
返回值异步调用后默认返回。主动发送消息,需在onmessage中解析并赋值。
生命周期TaskPool自动管理其生命周期,无需关注任务负载。开发者需自行管理Worker的数量和生命周期。
任务池个数上限自动管理,无需配置。同一进程下,最多支持同时开启64个Worker线程,实际数量由进程内存决定。
任务执行时长上限3分钟(不包含Promise和async/await异步调用的耗时,例如网络下载、文件读写等I/O任务的耗时),长时任务无执行时长上限。无限制。
设置任务的优先级支持配置任务优先级。从API version 18开始,支持配置Worker线程优先级。
执行任务的取消支持取消已经发起的任务。不支持。
线程复用支持。不支持。
任务延时执行支持。不支持。
设置任务依赖关系支持。不支持。
串行队列支持。不支持。
任务组支持。不支持。
周期任务支持。不支持。
异步队列支持。不支持。

适用场景对比

TaskPool和Worker均支持多线程并发能力。TaskPool的工作线程会绑定系统的调度优先级,并支持负载均衡(自动扩缩容),相比之下,Worker需要开发者自行创建和销毁,存在一定的创建和管理成本。因此,在大多数场景下,推荐优先使用TaskPool。

Worker适用于需要长时间占据线程,并由开发者主动管理线程生命周期的场景;TaskPool适用于执行相对独立任务的场景,任务在线程中执行时无需关注线程生命周期。

建议使用Worker的场景

以下场景中,任务通常需要长时间运行或依赖线程上下文,适合使用Worker:

  • 运行时间超过3分钟的任务

    (此处所说的3分钟不包括Promise和async/await异步调用的耗时,如网络下载、文件读写等I/O任务的耗时):

    例如后台进行1小时的预测算法训练等CPU密集型任务,适合使用Worker。

    场景示例可参考常驻任务开发指导

  • 有强关联的一系列同步任务

    例如在需要创建并使用句柄的场景中,每次创建的句柄都不同,且必须持续保存该句柄,以确保后续操作正确执行,此类场景适合使用Worker。

    场景示例可参考使用Worker处理关联的同步任务

建议使用TaskPool的场景

以下场景中,任务通常相对独立,对调度、取消或管理能力有更高要求,适合使用TaskPool:

  • 需要设置任务优先级的任务

    在API version 18之前,Worker不支持设置调度优先级,需要使用TaskPool;

    从API version 18开始,Worker支持设置调度优先级,开发者可以根据使用场景和任务特性选择使用TaskPool或Worker。

    例如图像直方图绘制场景,后台计算的直方图数据会用于前台界面的显示,影响用户体验,且任务相对独立,推荐使用TaskPool。

  • 需要频繁取消的任务

    如图库大图浏览场景。为提升体验,系统会同时缓存当前图片左右各两张图片。当往一侧滑动跳到下一张图片时,需取消另一侧的缓存任务,此时适合使用TaskPool。

  • 大量或调度点分散的任务

    例如大型应用中的多个模块包含多个耗时任务,不建议使用Worker进行负载管理,推荐使用TaskPool。

    场景示例可参考批量数据写数据库场景