[Code Design] Calling wait instead of Fiber.yield

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,846
First Language
English
In Game_Interpreter, there is a wait method that tells the thread to sleep for a given amount of time

def wait(duration) duration.times { Fiber.yield }endThere are also commands that say things like this

Code:
def wait_for_message  Fiber.yield while $game_message.busy?end
Where they explicitly yield instead of just calling something like wait(1)I'm not sure if there's really a difference between the two in terms of outcome, but it seems like it would be better to call the wait method instead of just calling Fiber.yield directly.

Thoughts?

EDIT: for clarification, what I mean is instead of saying something like

Code:
Fiber.yield while $game_message.busy?
How about saying something like

Code:
wait(1) while $game_message.busy?
Or even just defining a new wait method that simply does
Code:
Fiber.yield
 
Last edited by a moderator:

Hudell

Dog Lord
Veteran
Joined
Oct 2, 2014
Messages
3,545
Reaction score
3,715
First Language
Java's Crypt
Primarily Uses
RMMZ
Fiber.yield is better when you have a condition such as $game_message.busy?.

The purpose of the wait method is to skip a certain number of frames, instead of waiting for something to happen.
 

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,592
Reaction score
6,522
First Language
Indonesian
Primarily Uses
RMVXA
Nothing really different for both.

But, if you use "wait", it's more readable and you could alias and put some code to execute whenever "wait" method is called.
 

♥SOURCE♥

Too sexy for your party.
Veteran
Joined
Mar 14, 2012
Messages
693
Reaction score
411
Primarily Uses
In Game_Interpreter, there is a wait method that tells the thread to sleep for a given amount of time

def wait(duration) duration.times { Fiber.yield }endThere are also commands that say things like this

Code:
def wait_for_message  Fiber.yield while $game_message.busy?end
Where they explicitly yield instead of just calling something like wait(1)I'm not sure if there's really a difference between the two in terms of outcome, but it seems like it would be better to call the wait method instead of just calling Fiber.yield directly.

Thoughts?
I hope you're joking. The difference is very clear. One method waits an amount of frames, the other waits until a condition is met.
 

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,846
First Language
English
I hope you're joking. The difference is very clear. One method waits an amount of frames, the other waits until a condition is met.
I don't see much difference between

Code:
Fiber.yield while $game_message.busy?
Code:
wait(1) while $game_message.busy?
 

Hudell

Dog Lord
Veteran
Joined
Oct 2, 2014
Messages
3,545
Reaction score
3,715
First Language
Java's Crypt
Primarily Uses
RMMZ
It's the same, but when I see Fiber.yield, I can be sure there's nothing else going on.

If I see something like 

wait(1) while $game_message.busy?I'll always look for the "wait" method to make sure it's doing nothing else than yielding. Because I didn't even know the wait method existed and with past experiences I've learned to never trust a method name.

In short:

Fiber.yield is native to ruby, while wait is just a regular function.
 

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,513
Reaction score
3,203
First Language
Binary
Primarily Uses
RMMZ
In short:Fiber.yield is native to ruby, while wait is just a regular function.
Because of this, yielding will always reign superior. At least in terms of efficiency. ^_^
 
Last edited by a moderator:

♥SOURCE♥

Too sexy for your party.
Veteran
Joined
Mar 14, 2012
Messages
693
Reaction score
411
Primarily Uses
I don't see much difference between

Fiber.yield while $game_message.busy?
Code:
wait(1) while $game_message.busy?
wait(duration) is intended to be used when an event command needs to wait for a certain number of frames and not for a condition, it is a time related wait and not a condition related wait. There is a very big difference.

The following code will call a method that also calls .times for each frame just to finally do a Fiber.yield call:

wait(1) while $game_message.busy?The wait method:

def wait(duration) # It already took one method call to get here. duration.times do # .times call and iteration. Fiber.yield end endTry the following:

class Game_Interpreter def wait(duration) @method_calls += 2 duration.times { Fiber.yield } end def wait_for_message @method_calls = 0 wait(1) while $game_message.busy? p @method_calls endendAnd show a message via event commands. Then see how many method calls were performed while the program was waiting for player input.

This is not a joke, it is quite a serious concept that you need to understand in order to make scripts that perform efficiently. The code you proposed (wait(1) while $game_message.busy?)  is idiotic and not even a very bad programmer would use it. It's a level below "new to programming stuff" mistakes. To make it even more clear, it is in a similar level than this:

def self.id(id) idendIf you still don't see much difference between that and directly calling Fiber.yield while/until condition and you want to write better scripts, then it would helpful for you to take a break from RPG Maker and invest some time in learning basic programming concepts.
 

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,846
First Language
English
You're right, I don't appear to understand this very basic concept.

Can you explain to me what it is that your example is demonstrating and how using Fiber.yield is substantially different in terms of performance?

For example, is there a significant difference in the @method_calls variable in either approach?

@method_calls ||= 0#wait(1) while $game_message.busy? (1)#Fiber.yield while $game_message.busy? (2)p @method_callsAlso, what are the performance implications of using my wait approach over Fiber.yield?Is it going to cause serious problems?

I can see that there may be a few extra method calls but those seem pretty insignificant to me when I'm thinking of the benefits of funneling all "waiting" through a standard method.
 
Last edited by a moderator:

Hudell

Dog Lord
Veteran
Joined
Oct 2, 2014
Messages
3,545
Reaction score
3,715
First Language
Java's Crypt
Primarily Uses
RMMZ
It's not going to cause FPS drops or anything. It's just unnecessary.
 

♥SOURCE♥

Too sexy for your party.
Veteran
Joined
Mar 14, 2012
Messages
693
Reaction score
411
Primarily Uses
You're right, I don't appear to understand this very basic concept.

Can you explain to me what it is that your example is demonstrating and how using Fiber.yield is substantially different in terms of performance?
Yes, but I hope you don't ignore it like the last time (save files thing topic). I don't know about others, but if I take the time to educate you, I would appreciate an "Ok, got it" or a "Thanks" in response.

Grab this: https://github.com/evanphx/benchmark-ips

Then try the following:

def wait_good @i = 0 @i += 1 while @i < 60 end def wait_sum(n) n.times { @i += n } end def wait_bad @i = 0 wait_sum(1) while @i < 60 end require 'benchmark/ips' Benchmark.ips do |x| x.report("wait good") { wait_good } x.report("wait bad") { wait_bad } x.compare! endDo you see why this is a serious thing? If you don't understand why performing unnecessary method calls is a bad thing, you will end up making that mistake in other scripts that are more cpu intensive and that will have a significant, noticeable impact on performance.

Function calls are expensive, operations are expensive. Making unnecessary calls and operations makes your scripts unnecessarily slower and bad.

http://en.wikipedia.org/wiki/Instruction_pipeline

http://en.wikipedia.org/wiki/Computational_complexity_theory

http://en.wikipedia.org/wiki/Call_stack

http://en.wikipedia.org/wiki/Central_processing_unit

http://en.wikipedia.org/wiki/Instructions_per_second
 

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,846
First Language
English
Thanks, but I don't understand the significance of these numbers.

Since I am planning to wait one frame, it probably looks like this:

def wait_good @i = 0 @i += 1 while @i < 1 end def wait_sum(n) n.times { @i += n } end def wait_bad @i = 0 wait_sum(1) while @i < 1 end require 'benchmark/ips' Benchmark.ips do |x| x.report("wait good") { wait_good } x.report("wait bad") { wait_bad } x.compare! endSince I'm going to be waiting 1 frame as opposed to just yielding.

Code:
Calculating -------------------------------------           wait good    85.807k i/100ms            wait bad    77.480k i/100ms-------------------------------------------------           wait good      3.085M (± 6.2%) i/s -     15.359M            wait bad      1.892M (± 9.4%) i/s -      9.375MComparison:           wait good:  3085076.4 i/s            wait bad:  1892253.6 i/s - 1.63x slower
So one runs ~3 million instructions per second, another runs ~1.9 million instructions per second.From the numbers alone, we can see that one of them is running almost half as fast, but they're still fast enough for something that isn't going to be called that many times anyways.

Do you see why this is a serious thing? If you don't understand why performing unnecessary method calls is a bad thing, you will end up making that mistake in other scripts that are more cpu intensive and that will have a significant, noticeable impact on performance.
I always introduce as many methods as possible in every one of my scripts. If performance becomes a big issue that can be addressed separately.
 
Last edited by a moderator:

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,592
Reaction score
6,522
First Language
Indonesian
Primarily Uses
RMVXA
Here is the case...

If you have the wait code to be like this

def wait(duration) duration.times do update_1 update_2 update_3 Fiber.yield endendThen this is necessary

wait(1) while $game_message.busy?If not, just simply write this

Fiber.yield while $game_message.busy?Since I also use Fiber in my battle system to execute the action sequence. 

Thread sleep in my battle system is not simply put Fiber.yield, but also update many things. So only put Fiber.yield wont solve the problem
 

♥SOURCE♥

Too sexy for your party.
Veteran
Joined
Mar 14, 2012
Messages
693
Reaction score
411
Primarily Uses
I can see that there may be a few extra method calls but those seem pretty insignificant to me when I'm thinking of the benefits of funneling all "waiting" through a standard method.
Waiting for a specific number of frames is very different than waiting for a condition, you're trying to mix apples with pears just because they're both fruits.

Thanks, but I don't understand the significance of these numbers.

Since I am planning to wait one frame, it probably looks like this:

def wait_good @i = 0 @i += 1 while @i < 1 end def wait_sum(n) n.times { @i += n } end def wait_bad @i = 0 wait_sum(1) while @i < 1 end require 'benchmark/ips' Benchmark.ips do |x| x.report("wait good") { wait_good } x.report("wait bad") { wait_bad } x.compare! endSince I'm going to be waiting 1 frame as opposed to just yielding.

Code:
Calculating -------------------------------------           wait good    85.807k i/100ms            wait bad    77.480k i/100ms-------------------------------------------------           wait good      3.085M (± 6.2%) i/s -     15.359M            wait bad      1.892M (± 9.4%) i/s -      9.375MComparison:           wait good:  3085076.4 i/s            wait bad:  1892253.6 i/s - 1.63x slower
So one runs ~3 million instructions per second, another runs ~1.9 million instructions per second.From the numbers alone, we can see that one of them is running almost half as fast, but they're still fast enough for something that isn't going to be called that many times anyways.

I always introduce as many methods as possible in every one of my scripts. If performance becomes a big issue that can be addressed separately.
No. The < 60 thing was to represent the condition, not the number of frames. The condition from your original example is $game_message.busy?, I changed it so you can easily test it. < 1 is not closer to the original example's condition.

I always introduce as many methods as possible in every one of my scripts. If performance becomes a big issue that can be addressed separately.
That's a bad idea. Tools are to be used when needed, and knowing how to use the correct tool for the correct task at the correct time is part of programming. Besides, you probably wouldn't know where to start, otherwise we wouldn't be having this conversation.

You're short-sighted. Your inefficient script won't be the only custom script in the project of the people who uses it, many inefficient scripts together are more likely to produce performance issues even if each of them alone doesn't seem to affect performance much.

And there's still the thing where you're mixing two situations, wait(duration) has its job, which is to wait for a number of frames (its "wait condition" if you will, is the number of frames), Fiber.yield while/until condition has its job too, which is to "wait" while/until the condition is met.
 

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,846
First Language
English
Waiting for a specific number of frames is very different than waiting for a condition, you're trying to mix apples with pears just because they're both fruits.
But that's not what my code is doing.

def wait_for_message wait(1) while $game_message.busy?endYou could say it does both! :)
No. The < 60 thing was to represent the condition, not the number of frames. The condition from your original example is $game_message.busy?, I changed it so you can easily test it. < 1 is not closer to the original example's condition.
For me, these two accomplish the same thing.

Fiber.yield
Code:
1.times { Fiber.yield }
Except one of them is calling a bunch of methods and the other does not.This would incur the overhead of the method calls.

I would then assume these do the same thing

Fiber.yield while $game_message.busy?
Code:
1.times { Fiber.yield } while $game_message.busy?
 
And there's still the thing where you're mixing two situations, wait(duration) has its job, which is to wait for a number of frames (its "wait condition" if you will, is the number of frames), Fiber.yield while/until condition has its job too, which is to "wait" while/until the condition is met.
In the context of the Game_Interpreter, I don't see too much of a difference between

"wait one frame to pass until a condition has been met"

and

"wait until a condition has been met"
 
Last edited by a moderator:

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,592
Reaction score
6,522
First Language
Indonesian
Primarily Uses
RMVXA
In the context of the Game_Interpreter, I don't see too much of a difference between

"wait one frame to pass until a condition has been met"

and

"wait until a condition has been met"
The difference is the first one is unecessary.

Let reverse the question. Why you need to write?

wait(1) while $game_message.busy?Instead of

Code:
Fiber.yield while $game_message.busy?
 

♥SOURCE♥

Too sexy for your party.
Veteran
Joined
Mar 14, 2012
Messages
693
Reaction score
411
Primarily Uses
But that's not what my code is doing.

def wait_for_message wait(1) while $game_message.busy?endYou could say it does both! :)
For me, these two accomplish the same thing.

Fiber.yield
Code:
1.times { Fiber.yield }
Except one of them is calling a bunch of methods and the other does not.This would incur the overhead of the method calls.

I would then assume these do the same thing

Fiber.yield while $game_message.busy?
Code:
1.times { Fiber.yield } while $game_message.busy?
 In the context of the Game_Interpreter, I don't see too much of a difference between

"wait one frame to pass until a condition has been met"

and

"wait until a condition has been met"
Stop defending the indefensible. If you think it is okay, then go ahead and use it, but don't try to justify an awful design decision.

You asked for thoughts, you got thoughts and reasons why what you proposed is bad, you're free to do whatever you want though.

(Also your response following my "< 60" quote doesn't make sense)
 
Last edited by a moderator:

Jode

Warper
Member
Joined
Feb 9, 2014
Messages
3
Reaction score
8
First Language
English
Primarily Uses
I'd like to take this opportunity to quote M.A. Jackson:

Rules of Optimization:

 

Rule 1: Don't do it.

Rule 2 (for experts only): Don't do it yet.
While it's true that Fiber.yield will run faster than wait, unless, after extensive testing, you've determined it to be a bottle neck, don't worry about it. Don't even think about performance optimizations until you are absolutely certain you need to. It'll over complicate your code and waste your time.

That being said, in this case, I'd still recommend Fiber.yield over wait(1). As Hudell said, it is more readable, and guaranteed to have no side effects.
 

Lemur

Crazed Ruby Hacker
Veteran
Joined
Dec 1, 2014
Messages
106
Reaction score
124
First Language
English
Primarily Uses
Coming from the expert, rule 2 is best ignored in most all cases. You'll know better than to make silly performance mistakes by that point, and if you do they're minor enough not to even bother with.

Besides, there are tools which catch really bad ones for you. Consider Rails and the N + 1 query and the N^N query:

Code:
@user = User.find(1)@user.posts # Makes a new request for user posts@user.include(:posts).find(1) # Preload the association@users = user_ids.map { |id| User.find(id) } # That executes a query for every user. Really bad@users = User.where(id: user_ids) # One query for all users where their ID is in that collection
I guess the best way to put it is to say that rule 2 is irrelevant and should be updated as: Don't do it, let a tool do it for you.
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

Couple hours of work. Might use in my game as a secret find or something. Not sure. Fancy though no? :D
Holy stink, where have I been? Well, I started my temporary job this week. So less time to spend on game design... :(
Cartoonier cloud cover that better fits the art style, as well as (slightly) improved blending/fading... fading clouds when there are larger patterns is still somewhat abrupt for some reason.
Do you Find Tilesetting or Looking for Tilesets/Plugins more fun? Personally I like making my tileset for my Game (Cretaceous Park TM) xD
How many parameters is 'too many'??

Forum statistics

Threads
105,865
Messages
1,017,059
Members
137,574
Latest member
nikisknight
Top