Best Way to Use Threads

Godot Version

4.2.1

Question

Hi Everyone,

I’ve starting working on my pathfinding code for my game and I’ve been wanting to move the execution of all this code off onto another thread so the main thread doesn’t lag from the calculations being performed for this task. I was wondering what is the best way to do this.

For starters, I just made some test code that does an expensive calculation/loop to lag the main thread. Then I moved it to another thread. I found two methods online, and I was wondering which one was better, or if there is an even better way to do this?

This first method only starts the thread after it has already completed it’s previous task.

var thread : Thread

func _ready():
	# create thread
	thread = Thread.new()

func do_math(a, b, c):
	# Do some overly complicated laggy calculation
	a = 0
	for i in range(0, 10000000):
		a = a + i / 2000 + b + c
	print(a, " :: ", b, "::", c)

func _on_timer_timeout():
	# Have a timer call the thread every 1 second
	# If the thread is still processing the function, return
	if thread.is_alive() == false:
		# If the thread it started and finished, join it
		if thread.is_started():
			thread.wait_to_finish()
		# Once thread is finished, call thread to run function again
		thread.start(do_math.bind(1,2,3))
			
func _exit_tree():
	# On program exit, wait for the thread to finish
	thread.wait_to_finish()

The second one constantly runs a while loop in the separated thread, but a semaphore tells it when to run the calculation. ( I personally don’t think this one is as good as the above since the constantly running while loop is unnecessary processing even if on a different thread.)

var a = 0
var b = 0
var c = 0

var semaphore : Semaphore
var thread : Thread
var exit_loop = false

func _ready():
	thread = Thread.new()
	semaphore = Semaphore.new()
	thread.start(threadRun.bind(""))

func threadRun(userdata):
	while true: # Thread runs forever on one of your cores
		semaphore.wait() # Thread waits here on this line until receiving "semaphore.post()".
		
		if exit_loop:
			break
		
		a = 0
		for i in range(0, 10000000):
			a = a + i / 2000 + b + c
			
		self.call_deferred('math_done', a, b, c)
			
func math_done(a, b, c):
	print(a, "::", b, "::", c)
			
func _on_timer_timeout():
	# Have a timer call the semaphore every 1 second
	if semaphore != null:
		semaphore.post()
		
func _exit_tree():
	exit_loop = true
	semaphore.post()
	thread.wait_to_finish()

Thanks

I would say they are basically the same.

I would see if it is possibly to have the thread signal callback the data when it is done. This way you would not waste cycles checking the thread.

Since your requirements are straightforward, I’d recommend using this as an autoload:

It’s still similar to your approach but it might save you some time getting it working in your project