#WorkerThreadPool.add_task vs Lambdas
1 messages · Page 1 of 1 (latest)
2d top-down open-world action rpg. I'm creating a TileMapLayer using a bunch of noise generators
what value is the taskid for? I am assuming assigning jobs to dwarves citizens?
oh ok
This script has a couple of potential scoping and timing issues related to how taskId is managed and used. Let’s address these points systematically.
Observations and Issues
Initialization of taskId:
taskId is declared with :=, which initializes it as a local variable. However, if taskId is intended to be used outside this script or across function calls, it needs to be declared as a class member variable (e.g., var taskId = 0 without :=).
Timing and Deferred Call:
The call_deferred() method postpones execution of the inner function, which might cause a race condition if WorkerThreadPool.wait_for_task_completion(taskId) is called before the task is fully added or completed.
Task ID Access:
taskId is assigned immediately from WorkerThreadPool.add_task. If add_task is multi-threaded, ensure it returns the correct task ID before the deferred function accesses it.
Suggestions to Resolve the Issue
Scope of taskId:
If taskId needs to be accessed elsewhere, define it as a class member variable:
var taskId = 0
This ensures it persists beyond the scope of the current function.
Correct Task Management:
You should ensure WorkerThreadPool.wait_for_task_completion(taskId) is called only after the task is properly registered and execution has begun. Moving it out of the deferred function might make sense:
var taskId = WorkerThreadPool.add_task(func():
var chunk = chunk_generator.generate_chunk(chunkIndex)
add_child(chunk.terrainTileMapLayer)
chunks[chunkIndex] = chunk
chunksQueued.erase(chunkIndex)
)
WorkerThreadPool.wait_for_task_completion(taskId)
print("wait_for_task_completion: ", taskId)
Debugging Scope:
If taskId seems not to behave as expected, ensure no other local taskId is shadowing the variable in inner scopes. You can explicitly reference the class scope with self.taskId when needed:
self.taskId = WorkerThreadPool.add_task(...)
Check WorkerThreadPool Implementation:
Ensure that WorkerThreadPool.add_task and wait_for_task_completion are implemented correctly. If they rely on internal data structures for task management, debug to verify that the taskId provided is valid at the time wait_for_task_completion is called.
Defer Only UI or Visual Changes:
Keep deferred calls for tasks like UI updates or resource binding that truly need to wait for Godot's main thread.
If you need clarification or more details, feel free to provide more information on the errors or unexpected behaviors Gox is observing!
Here’s a rewritten version of Gox’s script with the recommendations applied and comments explaining each change:
Define taskId as a class member variable to ensure proper scope.
var taskId = 0
func process_chunk(chunkIndex):
# Add the task to the WorkerThreadPool and assign the taskId.
taskId = WorkerThreadPool.add_task(func():
# Generate the chunk in a separate thread.
var chunk = chunk_generator.generate_chunk(chunkIndex)
# Use a deferred call to add the TileMapLayer to the scene tree
# as scene tree operations must occur on the main thread.
(func():
add_child(chunk.terrainTileMapLayer)
chunks[chunkIndex] = chunk
chunksQueued.erase(chunkIndex)
).call_deferred()
)
# Wait for the task completion after adding the task.
# This ensures no race condition occurs with the task ID.
print("Task ID assigned: ", taskId)
WorkerThreadPool.wait_for_task_completion(taskId)
print("Task completed: ", taskId)
Explanation of Changes
taskId as a Class Variable:
Moved the taskId declaration outside the function and made it a class member variable. This ensures the ID persists across function calls and avoids scoping issues.
Separate Function:
The chunk processing logic is moved into a function (process_chunk) for better modularity. It helps organize the code and makes debugging easier.
Deferred Call for Scene Operations:
The add_child operation is encapsulated in a deferred function using call_deferred() because scene tree operations must be performed on the main thread in Godot.
Wait for Task Completion Outside Deferred Call:
The WorkerThreadPool.wait_for_task_completion(taskId) call is placed outside the deferred function to ensure it is executed immediately after the task is added. This avoids potential race conditions where the deferred call might delay task completion checks.
Debugging Prints:
Added debugging print statements to confirm the task ID and monitor when the task completes. This helps validate the workflow and identify any issues during runtime.
If Gox is still facing issues, we can further refine the script or look into specific parts of the implementation. Let me know if more details about WorkerThreadPool or chunk_generator are available!
oop it didnt copy perfect
var taskId = 0
func process_chunk(chunkIndex):
# Add the task to the WorkerThreadPool and assign the taskId.
taskId = WorkerThreadPool.add_task(func():
# Generate the chunk in a separate thread.
var chunk = chunk_generator.generate_chunk(chunkIndex)
# Use a deferred call to add the TileMapLayer to the scene tree
# as scene tree operations must occur on the main thread.
(func():
add_child(chunk.terrainTileMapLayer)
chunks[chunkIndex] = chunk
chunksQueued.erase(chunkIndex)
).call_deferred()
)
# Wait for the task completion after adding the task.
# This ensures no race condition occurs with the task ID.
print("Task ID assigned: ", taskId)
WorkerThreadPool.wait_for_task_completion(taskId)
print("Task completed: ", taskId)
and honestly chat gpt has been working pretty well for me since I gave it alot of training data, I gave it the entire godot directory, a bunch of books on godot, and a few dozen random scripts from the archive of 4.0
I also told it to not make stuff up
Thanks, but unfortunately, that solution would only support one thread at a time, and would block my main thread until that worker thread completed, leaving my game laggy when the player loads chunks.
I can ask for another, but geared for multithreading, which parts are incompatible?
I'm happy to send it more stuff, this is helping me learn
No thanks. There was a lot of incorrect and unhelpful information in its response.
i hope you figure it out this is all far above my league rn
Ignoring the taskId seems to work great, and is lightning fast, but I'm worried I'm going to cause a crash because I'm not calling wait_for_task_completion as recommended by the docs:
WorkerThreadPool.add_task(func():
var chunk := chunk_generator.generate_chunk(chunkIndex)
(func():
add_child(chunk.terrainTileMapLayer)
chunks[chunkIndex] = chunk
chunksQueued.erase(chunkIndex)
).call_deferred()
)