线程安全的 API
线程
线程是用来平衡各CPU和核心的处理能力.Godot支持多线程, 但不是在整个引擎中.
下面是可以在Godot的不同区域使用多线程的方法列表.
全局作用域
Most Global Scope singletons are thread-safe by default. Accessing servers from threads is supported. However, for the rendering and physics servers, thread-safe operation must be enabled in the project settings first.
This makes singletons ideal for code that creates dozens of thousands of instances in servers and controls them from threads. Of course, it requires a bit more code, as this is used directly and not within the scene tree.
场景树
Interacting with the active scene tree is not thread-safe. Make sure to use mutexes when sending data between threads. If you want to call functions or set properties from a thread, you may use call_deferred or set_deferred:
# Unsafe:
node.add_child(child_node)
# Safe:
node.add_child.call_deferred(child_node)
// Unsafe:
node.AddChild(childNode);
// Safe:
node.CallDeferred(Node.MethodName.AddChild, childNode);
但是, 可以在激活的场景树外创建场景块(以树形式排列的节点). 这样, 可以在线程中构建或实例化部分场景, 然后将其添加到主线程中:
var enemy_scene = load("res://enemy_scene.scn")
var enemy = enemy_scene.instantiate()
enemy.add_child(weapon) # Set a weapon.
world.add_child.call_deferred(enemy)
PackedScene enemyScene = GD.Load<PackedScene>("res://EnemyScene.scn");
Node enemy = enemyScene.Instantiate<Node>();
enemy.AddChild(weapon);
world.CallDeferred(Node.MethodName.AddChild, enemy);
Still, this is only really useful if you have one thread loading data. Attempting to load or create scene chunks from multiple threads may work, but you risk resources (which are only loaded once in Godot) being tweaked by the multiple threads, resulting in unexpected behaviors or crashes.
只有当你 "真正" 知道自己在做什么, 并且确信一个资源没有被多个资源使用或设置时, 才可以使用多个线程来生成场景数据. 否则, 直接使用服务端的API(它是完全线程安全的)而不接触场景或资源会更安全.
渲染
Instancing nodes that render anything in 2D or 3D (such as Sprite2D or MeshInstance3D) is not thread-safe by default. To run the rendering driver on a separate thread, set the Rendering > Driver > Thread Model project setting to Separate.
Note that the Separate thread model has several known bugs, so it may not be usable in all scenarios.
警告
You should avoid calling functions involving direct interaction with the GPU on other threads, such as creating new textures or modifying and retrieving image data. These operations can lead to performance stalls because they require synchronization with the RenderingServer, as data needs to be transmitted to or updated on the GPU.
物理
Physics simulation is not thread-safe by default. To run the physics servers on separate threads (making them thread-safe), enable the following project settings:
PhysicsServer2D: Physics > 2D > Run on Separate Thread.
PhysicsServer3D: Physics > 3D > Run on Separate Thread.
GDScript arrays and dictionaries
In GDScript, reading and writing elements from multiple threads is OK, but anything that changes the container size (resizing, adding, or removing elements) requires locking a mutex.
资源
Modifying a unique resource from multiple threads is not supported. However, handling references on multiple threads is supported. Hence loading resources on a thread is as well - scenes, textures, meshes, etc - can be loaded and manipulated on a thread and then added to the active scene on the main thread. The limitation here is as described above: one must be careful not to load the same resource from multiple threads at once. Therefore, it's easiest to use one thread for loading and modifying resources, and then the main thread for adding them.