线程安全的 API
线程
线程是用来平衡各CPU和核心的处理能力.Godot支持多线程, 但不是在整个引擎中.
下面是可以在Godot的不同区域使用多线程的方法列表.
全局作用域
Global Scope singletons are all thread-safe. Accessing servers from threads is supported (for RenderingServer and Physics servers, ensure threaded or thread-safe operation is enabled in the project settings!).
这使它们成为在服务器中创建数十万个实例并从线程控制它们的代码的理想选择. 当然, 还需要更多的代码, 因为这是直接使用的而不是嵌入场景树中使用.
场景树
与活动场景树的交互是线程 不 安全的. 当在线程之间发送数据时, 请确保使用mutexes. 如果你想从一个线程调用函数, 可以使用 call_deferred 函数:
# Unsafe:
node.add_child(child_node)
# Safe:
node.call_deferred("add_child", child_node)
但是, 可以在激活的场景树外创建场景块(以树形式排列的节点). 这样, 可以在线程中构建或实例化部分场景, 然后将其添加到主线程中:
var enemy_scene = load("res://enemy_scene.scn")
var enemy = enemy_scene.instantiate()
enemy.add_child(weapon) # Set a weapon.
world.call_deferred("add_child", enemy)
不过, 只有当你有 一个 线程加载数据时, 这才真正有用. 从多个线程加载或创建场景块可能有效, 但你要冒着资源被多线程调整的风险(在Godot中只加载一次), 从而导致意外行为或崩溃.
只有当你 “真正” 知道自己在做什么, 并且确信一个资源没有被多个资源使用或设置时, 才可以使用多个线程来生成场景数据. 否则, 直接使用服务端的API(它是完全线程安全的)而不接触场景或资源会更安全.
渲染
Instancing nodes that render anything in 2D or 3D (such as Sprite) is not thread-safe by default. To make rendering thread-safe, set the Rendering > Driver > Thread Model project setting to Multi-Threaded.
请注意,Multi-Thtreaded 线程模型有若干已知的问题,所以无法胜任所有场景。
你应该避免调用涉及与其他线程上的GPU直接交互的函数,例如创建新纹理或修改和检索图像数据,这些操作可能会导致性能停滞,因为它们需要与 :ref:`RenderingServer<class_RenderingServer>`同步,因为数据需要传输到GPU或在GPU上更新。
GDScript 数组、字典
在 GDScript 中,可以从多个线程读取和写入元素,但是任何改变容器大小的操作(调整大小、添加或删除元素)都需要锁定互斥锁。
资源
不支持从多个线程修改一个唯一的资源. 但是支持处理多个线程上的引用, 因此在一个线程上加载资源也是如此, 场景, 纹理, 网格等都可以在一个线程上加载和操作, 然后添加到主线程的活动场景中. 这里的限制如上所述, 必须注意不要同时从多个线程上加载相同的资源, 因此最简单的方法是用 一个 线程来加载和修改资源, 然后用主线程来添加资源.