> Creating threads is a slow operation, especially on Windows. \- [[Godot]] documentation[^1] It is best to build a thread pool and re-use threads. # Environment ## Types The `Vector` and `PackedArray` types uses atomic operations to maintain thread safety.[^2] `Variant` is another atomic type. The documentation does not explain which operations on these types are atomic, but presumably not all of them are. ## Thread Groups `PROCESS_THREAD_GROUP_INHERIT` is the default for new nodes and they will just inherit whatever thread group their parent has. `PROCESS_THREAD_GROUP_MAIN_THREAD` ensures that a node evaluates on the main thread. This is necessary for anything which draws to the screen. The top node `root` (or something above it internally) has this set for it. `PROCESS_THREAD_GROUP_SUB_THREAD` spawns a node in a new thread. Its sub-nodes will follow it to that same thread unless they are specifically set to `PROCESS_THREAD_GROUP_MAIN_THREAD` (which should probably not usually happen). ## Functions # Working With ## Communicating with the Main Thread The subthreads need a way to send results back to the main thread. While this feature is not mentioned in the official documentation for the `call_deferred` function, it can apparently be used to send information back to the main thread. ### Call Deferred by Name It is a function inherited from `Object` which will run a given function by name during "idle" time *after* the main processing callbacks have finished. ```python func background_thread_process(): result = 1 + 1 %some_other_node.call_deferred("inbox_function", result) ``` ### Call Deferred Callable Callable objects like function references may be directly invoked. ```python func background_thread_process(): result = 1 + 1 %some_other_node.inbox_function.call_deferred(result) ``` ### Call Deferred Thread Group This function is run *before* the main processing callbacks and notifications have started. ```python func background_thread_process(): result = 1 + 1 %some_other_node.call_deferred_thread_group("inbox_function", result) ``` ### Call Thread Safe Acts just like `call`, unless the receiver is running in another thread, then it acts just like `call_deferred`. This allows a single function to work in both threaded and non-threaded contexts. ```python func background_thread_process(): result = 1 + 1 %some_other_node.call_thread_safe("inbox_function", result) ``` | Function | Use | | ------------------------------ | ------------------------------------------------ | | `set_deferred_thread_group` | Set property *before* processing | | `set_thread_safe` | Set property *immediately* or *after* processing | | `notify_deferred_thread_group` | | | `notify_thread_safe` | | ## Built-In Tools ### Worker Thread Pool The `WorkerThreadPool`[^3] class provides some basic thread pool functionality. # Uses ## Tree Building The documentation[^2] recommends building new trees in a thread and then adding them (with `node.add_child()`) in the main thread. # Limitations ## Kill Threads Godot provides no way to kill threads. # References - https://docs.godotengine.org/en/stable/classes/class_thread.html - https://docs.godotengine.org/en/stable/classes/class_node.html#enum-node-processthreadgroup - https://stackoverflow.com/questions/77053783/a-big-question-on-multi-threading-and-its-nuances-what-is-it-and-how-to-work-wi ## Footnotes [^1]: https://docs.godotengine.org/en/stable/tutorials/performance/using_multiple_threads.html [^2]: https://docs.godotengine.org/en/stable/tutorials/performance/thread_safe_apis.html [^3]: https://docs.godotengine.org/en/stable/classes/class_workerthreadpool.html#class-workerthreadpool