Unity 的 Job 系统允许您创建多线程代码,以便您的应用程序可以使用所有可用的 CPU 内核来执行您的代码。这可以提高性能,因为您的应用程序更有效地利用了它运行的所有 CPU 内核的容量,而不是将所有代码在一个 CPU 内核上运行。
您可以单独使用 Job 系统,但为了提高性能,您还应该使用 Burst 编译器,该编译器专门设计用于为 Unity 的 Job 系统编译 Jobs。Burst 编译器改进了代码生成,从而提高了性能并减少了移动设备上的电池消耗。
您还可以将 Job 系统与 Unity 的 实体组件系统 一起使用,以创建高性能数据导向代码。
Unity 使用自己的原生 Job 系统来处理多个工作线程上的自己的原生代码,这些线程取决于应用程序运行的设备上可用的 CPU 内核数量。通常,Unity 在一个线程上执行您的代码,该线程在程序启动时默认运行,称为主线程。但是,当您使用 Job 系统时,Unity 会在工作线程上执行您的代码,这称为多线程。
多线程利用了 CPU 跨多个内核同时处理大量线程的能力。任务或指令不是一个接一个地执行,而是同时运行。工作线程并行运行,并在完成时将其结果与主线程同步。
Job 系统确保线程数量仅足以匹配 CPU 内核的容量,这意味着您可以在不确切知道有多少个 CPU 内核可用情况下安排您需要的任何任务。这与其他依赖于线程池等技术的 Job 系统不同,在这些系统中,更容易创建比 CPU 内核更多的线程,从而导致效率低下。
Job 系统使用工作窃取作为其调度策略的一部分,以平均分配跨工作线程共享的任务量。工作线程可能比其他线程更快地处理任务,因此,一旦工作线程完成处理所有任务,它就会查看其他工作线程的队列,然后处理分配给另一个工作线程的任务。
为了更轻松地编写多线程代码,Job 系统具有一个安全系统,可以检测所有潜在的竞争条件并保护您免受这些条件可能导致的错误。竞争条件发生在当一个操作的输出取决于它无法控制的另一个进程的计时时。
例如,如果 Job 系统从主线程中的代码中向一个 Job 发送对数据的引用,它无法验证主线程是否正在读取数据,而同时 Job 正在写入数据。这种情况会造成竞争条件。
为了解决这个问题,Job 系统会向每个 Job 发送它需要操作的数据的副本,而不是向主线程中的数据发送引用。这个副本隔离了数据,从而消除了竞争条件。
Job 系统复制数据的方式意味着 Job 只能访问可直接映射数据类型。这些类型在托管代码和原生代码之间传递时不需要转换。
Job 系统使用memcpy 来复制可直接映射数据类型并在 Unity 的托管部分和原生部分之间传输数据。它使用 memcpy 在调度 Jobs 时将数据放入原生内存,并在执行 Jobs 时为托管端提供对该副本的访问。有关更多信息,请参阅调度 Jobs。
除了核心 Unity 引擎中提供的 Job 系统之外,集合包还扩展了许多Job 类型和原生容器。有关更多信息,请参阅集合文档。