ID:1978896
 
After Kozuma's post, I went ahead and tried to extrapolate on the idea as much as I could whilst keeping it still logical. I apologize if there's any logic errors in here, I haven't tested it yet. At the bottom I'll post a bit of a tutorial as to the advantages and why you should be using it and how.

var
mainUpdateLoop
mainUpdateLoop = new()
list
newWorldLoops = list("movement" = 0)
proc
addUpdater(var/name,var/updater)
if(name in mainUpdateLoop.updateLoops)
var/updateLoop/UL = mainUpdateLoop.updateLoops[name]
UL.updateLoop |= updater

#ifdef DEBUG
else
CRASH("Update Loop Crash. Tried to add \"[updater:type]\" to a loop that doesn't exist: \"[name]\".")
#endif
removeUpdater(var/name,var/updater)
if(name in mainUpdateLoop.updateLoops)
var/updateLoop/UL = mainUpdateLoop.updateLoops[name]
UL.updateLoop -= updater

#ifdef DEBUG
else
CRASH("Update Loop Crash. Tried to remove \"[updater:type]\" to a loop that doesn't exist: \"[name]\".")
#endif


createLoop(var/name,var/speed)
if(!(name in mainUpdateLoop.updateLoops))
var/updateLoop/UL = new()
UL.name = name
UL.iterationSpeed = speed
mainUpdateLoop.updateLoops[name] = UL
pauseLoop(var/name)
if(name in mainUpdateLoop.updateLoops)
var/updateLoop/UL = mainUpdateLoop.updateLoops[name]
UL.pause =! UL.pause

#ifdef DEBUG
else
CRASH("Update Loop Crash. Tried to pause a loop that doesn't exist: \"[name]\".")
#endif
forceUpdate(var/name)
if(name in mainUpdateLoop.updateLoops)
var/updateLoop/UL = mainUpdateLoop.updateLoops[name]
UL.delay = 0

#ifdef DEBUG
else
CRASH("Update Loop Crash. Tried to force update a loop that doesn't exist: \"[name]\".")
#endif

mainUpdateLoop
var
list
updateLoops = new/list()
New()
mainUpdateLoop = src
for(var/v in newWorldLoops)
createLoop(v,newWorldLoops[v])
..()
update()

proc
update()
spawn for()
for(var/updater in updateLoops)
var/updateLoop/UL = updateLoops[updater]
UL.iterate()
sleep world.tick_lag

updateLoop
var
list
updateLoop = new/list()
iterationSpeed = 0
pause = 0
delay = 0
name = ""

proc
iterate()
if(!pause)
if(!delay)
delay = iterationSpeed
update()
else
delay --

update()
for(var/updater in updateLoop)
if(hascall(updater,"update"))
updater:update()
#ifdef DEBUG
else
CRASH("Update Loop Crash. Tried to call iterate on \"[updater:type]\", in \"[name]\".")
#endif DEBUG





Quick rundown of what this does:
At the start of your world, a mainUpdateLoop is created, which continuously loops through all of the updateLoops you create, and iterates them. Iterating them means that it checks everything within the updateLoop, and runs the update() function for it.

The advantages to using a large single updateloop like this, is that it runs a lot lot quicker than having lots of individual loops. So for example, if you have your mob's AI in a loop, which randomly moves them around, and you have 1000 mobs, it will be significantly slower running than if you have one loop, which checks 1000 mobs and lets them run their movement.

To make it work, call createLoop(var/name,var/speed) to create a loop and it'll automatically get added to the mainUpdateLoop. Then call addUpdater(var/name,var/updater) to add anything to the loop, but make sure that whatever you add has the update() proc defined for it. You can force update a loop using forceUpdate(var/name), and remove things from loops using removeUpdater(var/name,var/updater). Finally you can pause and unpause loops using pauseLoop(var/name). newWorldLoops is a list in which you can define lists spawned on the creation of a new world, this is handy because it stops runtime errors if you have atoms initialized in the map editor.

Have fun, and play around as much as you can!

I apologise if I'm bad at explaining, but I talk to Kaiochao a lot, and he's bad at explaining. So blame him.
If you wanna go all out on something like this, there's always this.
So I changed how I did this a while ago, whilst PJB's is definitly the be all end all, it's not particularly lightweight which is what I was going for. After stripping out a lot of the features I found myself rarely using, and adding a datum var (Not good practice really, but I was using update loops for literally everything so shrug), I found this to be far more user friendly and easier to get on with. I've also removed the different time loops, since I ended up just using timers for everything, which is probably better practice. Using more memory on BYOND is always better than using more CPU (To a point)

datum
var
updater = 0

proc
update()

Del()
if(updater)removeUpdater(src)
..()

var
updateLoop
updateLoop = new()

proc
addUpdater(var/datum/updater)
updateLoop.updaters |= updater
updater.updater = 1

removeUpdater(var/datum/updater)
updateLoop.updaters -= updater
updater.updater = 0

updateLoop
var
list
updaters = list()

New()
spawn loop()

proc
iterate()
for(var/datum/D in updaters)
D.update()

loop()
for()
iterate()
sleep(world.tick_lag)
For a slightly more advanced but just as simple global looping system you can give this a glance.
http://www.byond.com/developer/Kozuma3/kLoops