How to multithread

Godot Version

4.3

Question

I am working on a simulation and I am trying to optimize it with multithreading. Each simulation tick a certain amount of objects called pops are updated which is already faster than updating them all at once, but I am still trying to see if I can have more pops updating at the same time so I tried multithreading but I keep running into the issue of the thread not finishing in time so it throws an error? How do I properly multithread my project?

func updatePops():
	var popsUpdated : Array[Pop] = []
	var threadedPopsUpdated : Array[Pop] = []
	
	# Creates iterator
	var i : int  = 0
	for pop : Pop in pops:
		# Goes through all our pops and if the pops update tick is the same
		if (pop.updateTick == (timeManager.day/timeManager.daysPerTick)):
			# We add it to one of the two arrays for processing
			match(i):
				0:
					popsUpdated.append(pop)
				1:
					# TODO: Properly multithread this
					threadedPopsUpdated.append(pop)
			i += 1
			if (i > 1):
				i = 0
	# Updates our pops on threads
	popThread.start(updatePopArray.bind(threadedPopsUpdated))
	updatePopArray(popsUpdated)

# Grows pop populations
func updatePopArray(pops : Array[Pop]):
	for pop : Pop in pops:
		# Gets pop birth rate
		var bRate = pop.birthRate
		if (pop.region.population > 10000):
			# If the region is overpopulated apply a 25% decrease to birth rates
			bRate *= 0.75
		# Gets our natural increase trate
		var NIR : float = bRate - pop.deathRate
		# Flat increase rate
		var increase = int(float(pop.population) * NIR)
		# Gets the decimal from the NIR multiplied by population and uses it as a chance for one more person to exist
		if (randf() < abs(fmod(float(pop.population) * NIR, 1))):
			# If that person exists (Or dies) change population
			increase += sign(NIR)
		# Updates the pop's population
		pop.changePopulation(increase)

How much threading have you done before? A “simple” start would be a thread pool. It’s a complex subject but generally there’s a big difference between having a program use a thread to do some background stuff, vs having a program split time sensitive work between multiple threads and orchestrate it all correctly (and quickly).

2 Likes

This is my first attempt at multithreading in Godot.

Have you seen WorkerThreadPool?

This says you can have multiple threads interact with a single dict / array. You should be able to just calculate different indices and have thread pool workers operate on different parts of your pop array.

I’ve never tuned for cache lines or anything but a simple worker pool should give easy results. Just make sure you throw a lot of work at multithreaded setups so thread syncing/waking/spinning/scheduling isn’t taking up a disproportionate amount of cycles compared to actually updating pops.

A bit late but from another angle – do you need to multithread if you change the abstraction?

example: Stellaris has had all kinds of stupid performance problems in large part because they insisted on simulating individual pops for little gameplay benefit. (Their technical devlogs are quite interesting for any simulation dev btw)

So… what I’m suggesting is maybe you iterate regions because the number is much much smaller.

1 Like

Late for a response but that is actually what I ended up going with. I still had to multithread but I got a tiny performance benefit from it

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.