ID:1599489
 
Keywords: sleep, spawn
(See the best response by Lige.)
Code:
proc/EventLoop()
spawn(60000)
world << "Blah blah blah"
EventLoop()

proc/EventLoop()
:xpevent
sleep(60000)
world << "blah blah blah"
sleep(60000)
world << "blah blah blah"
goto xpevent


Problem description:

Spawn() vs Sleep()

Is it better to use Spawn() or Sleep() in a infinite loop?

What kind of proc would be best used for this?
I believe spawn() is better to use.
Best response
I'd go with sleep() since you should be making use of while() in the event of an infinite loop.
It depends really.
Sometimes using sleep will cause problems or errors since sleeping an atom may "lock up" it's usage or halt it, you may need some things to keep going. For instance say you sleep a player, but during that time it is being struck by another player- the damage may not register until a few seconds later depending on how things are set up if you are using sleep, using the spawn method however will work fine and is usually preferred as SSj said.

The second instance, you shouldn't use except under extreme circumstances.
A while loop with a sleep at the end is the same thing as your second example, which Lige pointed out.

One tactic I use is to create an object that handle whatever function. For instance if I wanted to create a day and night cycle. I'd create a weather controller, that infinitely loops within a proc that is contained on the object itself. *I usually use the spawn for this*. This object then handles everything associated with day and night cycles. This is also a method useful for auto-saving player's games and many other techniques.

One important thing is you have to remember to turn off world.loop_checks (set to 0) - otherwise your project will eventually shut down from detecting an infinite loop after a few minutes as a precaution.
In response to Dariuc
Dariuc wrote:
It depends really.
Sometimes using sleep will cause problems or errors since sleeping an atom may "lock up" it's usage or halt it, you may need some things to keep going. For instance say you sleep a player, but during that time it is being struck by another player- the damage may not register until a few seconds later depending on how things are set up if you are using sleep

Can you construct an example showing this? I don't particularly follow.

In response to Stephen001
Stephen001 wrote:
Dariuc wrote:
It depends really.
Sometimes using sleep will cause problems or errors since sleeping an atom may "lock up" it's usage or halt it, you may need some things to keep going. For instance say you sleep a player, but during that time it is being struck by another player- the damage may not register until a few seconds later depending on how things are set up if you are using sleep

Can you construct an example showing this? I don't particularly follow.
TakeDamage()
animate(src,alpha=0,time=5,loop=3)
sleep(15)
hp-=5


In the event that you strike a player two times in a row or unleash a combo, the damage won't show up for 1.5 secs. Albeit there are dozens of better ways to do this. Like just using flick to show a damage animation.

It's more a matter of timing, especially if you have some sort of combo system set up.

The point I was making is if an atom is sleeping, sometimes other actions that are expected to occur due to timing often won't.

Where as using spawn in the previous example would fix that problem altogether.

Edit:
To elaborate a little further. Let's say you have a poison loop- that uses TakeDamage as written above. This loop poisons the player for hp damage over time for say.. idk 600 ticks.

Couple that with actual combat, and you have what is known in some circles as a "clusterf***"
I guess, and I appreciate the example is a bit contrived, which maybe doesn't help here, particularly as the problem isn't sleep, or spawn, it's that you've decided to make TakeDamage() rely on presentation finishing (animate) to dictate when a state change occurs (the HP reduction).

The thing is, (and this is kind of what you're illustrating) is sleep() and spawn() have different behaviour. With the sleep(), the caller can't really spam this procedure, which might be desirable in some contexts (damage over time scenarios for instance, like poison, come to mind), but not in others (like your attack combo/action scenario).

I mean same goes, you could probably use neither in that attack combo example, make the damage apply instantly and leave animate as the visual effect it is, an indicator to the player and nothing more, separate presentation and state change. But yeah ... like you said, dozens of better ways of doing it etc.

I guess in response to OP's scenario (an event loop), sleep() inside the loop, spawn() around the loop, as OP actually demonstrates, /usually/.

@NarutoBleach: Do you have a more 'real world' example, like what are you actually trying to do with this particular loop?



proc/EventLoop()
if(Serverxp)
goto WAIT
:XPEVENT
Serverxp=1
world <<"<b><font color=red size=2>EVENT: </font><font color=yellow size=2><b>A EXP event has been started! Simply kill any enemy and you will gain extra exp.</font>"
:WAIT
sleep(18000)
Serverxp=0
world <<"<b><font color=green size=2>EVENT: </font><font color=white size=2><b>EXP event has been disabled! You will no long receive extra exp from kills.</font>"
GoldEvent=2
world <<"<font color=red size=2><b>EVENT: <font color=yellow size=2><b>Increased money gain from Hollows active! Gold gain is level based and income helps a lot.</font>"
sleep(18000)
GoldEvent=1
world <<"<b><font color=green size=2>EVENT: </font><font color=white size=2><b>The Gold & Honor Event is now over.</font>"
goto XPEVENT


LOL. This is my loop I use to call events.
And I guess, Serverxp etc are global variables?

Aside from the spaghetti goto use, it seems fine to me! Maybe add a variable to protect against duplicate running, and you're golden.

var/eventLoopStarted = 0

proc/EventLoop()
if (!eventLoopStarted)
eventLoopStarted = 1
spawn() // This will let us return execution to the caller of EventLoop() so we don't block them.
while(1)
Serverxp = 1
world <<"<b><font color=red size=2>EVENT: </font><font color=yellow size=2><b>A EXP event has been started! Simply kill any enemy and you will gain extra exp.</font>"
sleep(18000)
Serverxp = 0
world <<"<b><font color=green size=2>EVENT: </font><font color=white size=2><b>EXP event has been disabled! You will no long receive extra exp from kills.</font>"
GoldEvent = 2
world <<"<font color=red size=2><b>EVENT: <font color=yellow size=2><b>Increased money gain from Hollows active! Gold gain is level based and income helps a lot.</font>"
sleep(18000)
GoldEvent = 1
world <<"<b><font color=green size=2>EVENT: </font><font color=white size=2><b>The Gold & Honor Event is now over.</font>"


I call spawn() EventLoop() in world.New(). And I use the goto because I sometimes start XPevent myself.


Thank you for helping guys. :)
No problem. The advantage of building it into the procedure is just so you don't have to care. I mean in this case, you're probably only calling it once, and it's called 'EventLoop' so you probably know it's going to be long-running :P

The correction of the goto use was a bug fix, too. If you called EventLoop twice (which .. you know, would be a bug) and caught it around these parts:

world <<"<b><font color=green size=2>EVENT: </font><font color=white size=2><b>EXP event has been disabled! You will no long receive extra exp from kills.</font>"
GoldEvent=2
world <<"<font color=red size=2><b>EVENT: <font color=yellow size=2><b>Increased money gain from Hollows active! Gold gain is level based and income helps a lot.</font>"
sleep(18000)


You'd end up with two event loops running forever, and so ... twice the set of messages etc. The conversion to while() and use of var/eventLoopStarted = 0 just fixes that, so calling EventLoop() twice is harmless.

Edit: Sorry, just read your reply. So you like ... what ... intentionally want to run two or more event loops sometimes ... or? The first if statement kinda makes it seem like you didn't want to support that.
If I did
spawn() src << "hmm"


how long would it take before that code runs? I know it's 0 seconds, but if I had bunch of codes after it, will spawn() run after all the codes are done or it'll be in the middle of the code?
It'll spawn after the code following it has finished. So for example:

proc/spawnedThing()
world << "Yo, I was the spawned code!"

client/verb/Show_How_Spawn_Works()
world << "We're going to spawn a thing, then do work, and see when it runs."
sleep(1)
spawn() spawnedThing()
for (var/i in 1 to 1000000)
var/k = sqrt(i ** i)
world << "I've just finished doing work."
I understand that it'll run if you go to sleep, but what if it wasn't sleep, but say 500 lines of code (exaggeration). What will happen then?
Sorry, I probably updated the example before you replied. If you run the example above, you'll see the spawned code will execute after the verb finishes (assuming you don't get a nice BYOND warning message about "infinite loop detected").

If we throw a sleep in there, then yeah, the spawned code runs when we sleep. There's basically only one thing actually executing at a time, and sleep stops the currently running thing, which then allows spawned code to run.
using any loops like while() and for(), i'll use sleep().

If its just a proc calling another proc, I'll use spawn()
I'm running it, and I'm just wonder how the order stacks. The for loop is after spawn() so it's understandable that it'll finish running before spawn(). And the world message was immediately following it.

What I'm trying to ask is,
Spawn() runs after the all code following it as long as there's no Sleep().

It'll stack everything after spawn() and spawn() come after.
"Spawn() runs after the all code following it as long as there's no Sleep()."

Yes, that's basically it. It's not just limited to sleep(), though, there are a few other procedures that sleep a procedure (world.Import() comes to mind) that will allow any spawn()'d code to run.
A good way to think about it is that spawn() will allow whats under it's tree run after the time you set to wait. If no time is set, it is safe to assume it will run along side the rest of the code that's not under the spawn() tree.

Using sleep(), it will complete the process's, wait a time set, continue the process's, etc.


--


Think of spawn() as run along-side and sleep() as run one-at-a-time.

That's my best help for that.
If a proc was on hold, and like 20 players is doing the same thing would this cause lags?
Page: 1 2