Multithreading is not a trivial task, and you probably don’t need to manually use it unless you have a cpu bottle-neck somewhere, or if you have something that really benefits from parallel execution.
Spinning up a new thread has overhead. Accessing heap memory has overhead. If you’re only using it for a few seconds it’s not going to be worth it. It doesn’t look like you’re function actually does anything either…so it’s not a good indicator of multithread efficiency. You’re getting all overhead, no work!
Dispatching 12 threads and iteratively decrementing an integer per-thread causes that much overhead?
I tried doubling the decrement count and each thread now takes 7 times longer (84 seconds) to process than if it were single-threaded. Is that all overhead?
Isn’t multithreading designed to handle iterative processes like this? Like A* pathfinding?
Isn’t it counter-intuitive if it results in such extreme overhead and slows down other processes massively?
qdeanc | 2022-02-16 01:43
Is this a debug build? Or a release build? Did you try the profiler to see where the time is being spent?
Decrementing an integer is not a real world use-case for multithreading. Have you considered trying something more complicated?
I definitely am no expert on multithreading, so if you actually know what you are talking about please let me know and I’ll step back from this conversation.
rossunger | 2022-02-16 03:47
Is mentioned above, I’m using 3.4.2 - stable, which is the latest release build.
Decrementing an integer isn’t a real world use-case, but I’d like to know why it’s hurting performance anyways; and in 8+ hours of reading articles and forum threads on multithreading bottlenecks for general programming, I haven’t come across any mention of overhead from heap allocation. The profiler shows minimal memory usage and expected CPU usage, as the threading maxes out all of my CPU cores.
That being said, I’ve swapped out the decrement function for a function that counts prime numbers within a range, which is a lot like decrementing but with a division operation and conditional statement. As far as the logic goes, it’s very similar to a pathfinding algorithm (lots of conditional statements and memory allocations), which is a common function used in multithreading. The performance still suffers from multithreading, though.
I’m still learning all this myself, and I appreciate your efforts, but I think that blaming the performance hit on general overhead is leading me in the wrong direction. That is unless Godot specifically suffers from multithreading overhead.
qdeanc | 2022-02-16 04:50
If you’re running in editor, that’s a debug build… If you export the project and run without editor that’s a release build in my mind.
Didn’t mean to point you in the wrong direction! Sorry. I’m kinda curious myself now. Please let us know if you find anything.
rossunger | 2022-02-16 04:55
Also, curious to see if you try the same thing but in c++ via a gdnative plugin if it has the same result? And also in a standalone c++ app.
rossunger | 2022-02-16 04:57
I just tried exporting the game to an exe (debug build) and the multithreading works fine.
Splitting the decrementing operation between 6 threads now brings the processing time down from 6 seconds to roughly 1.2 seconds per thread.
Thank you for reminding me. I guess that solves everything. Sorry, I should have tried that before even posting!!
qdeanc | 2022-02-16 05:21
And yeah it’s totally overhead from running it in the editor ;-;
qdeanc | 2022-02-16 05:55