Nothing Special   »   [go: up one dir, main page]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flow order of execution #14

Closed
brettmjohnson opened this issue May 29, 2021 · 6 comments
Closed

Flow order of execution #14

brettmjohnson opened this issue May 29, 2021 · 6 comments

Comments

@brettmjohnson
Copy link

In debugging, I found the order of execution when using Flow was a little unexpected. It might be worth documenting.

For example, in an Update function (not real code):

  • print("testA")
  • flow( print("testB") ) -- no delay before calling print
  • print("testC")

I was expecting it to print testA, testB, testC. Instead it's testA, testC, testB. They're all executed on the same frame, but Flow executes later.

This is totally fine but might be worth noting somewhere.

Also, thanks for the great toolset, and all your assets really.

@britzl
Copy link
Owner
britzl commented May 30, 2021

You're right. There is a one frame delay before the first line of code in a flow is executed. I can't even remember why it is that way and I even have a unit test that checks this... It honestly feels a bit strange. I would probably expect flow.start() to start running code immediately, just like a coroutine.create() + resume() does...

@brettmjohnson
Copy link
Author

Oh, wow, I thought it all started on the same frame, just later. But I tested in another way just now and I see what you mean.

Where do coroutines get run in order of execution? I checked https://defold.com/manuals/application-lifecycle/ but didn't see them.

Coming from Unity, Lua's coroutines are a little odd at first glance and Flow more closely matches my mental model. Ideally, it would start on the same frame. But if they can't for some reason, I guess I should look at standard coroutines for certain use cases.

@brettmjohnson
Copy link
Author
brettmjohnson commented May 30, 2021

Okay, I dug into things a little and I think frame delay may come from in the function create_or_get:

			timer_id = timer.delay(0, true, function(self, handle, time_elapsed)
				if not instances[co] then
					timer.cancel(handle)
					return
				end
				update_flow(self, time_elapsed, co)
			end),

That time.delay set to 0 runs the code on the next frame. But the time.delay is setting up the update function for each flow every frame, so it seems pretty integral.

A possible solution is to add another update_flow after instances[co] is created:

local function create_or_get(co)
	assert(co, "You must provide a coroutine")
	if not instances[co] then
		id_counter = id_counter + 1
		instances[co] = {
			id = id_counter,
			url = msg.url(),
			state = READY,
			co = co,
			timer_id = timer.delay(0, true, function(self, handle, time_elapsed)
				if not instances[co] then
					timer.cancel(handle)
					return
				end
				update_flow(self, time_elapsed, co)
			end),
		}
		update_flow(nil, 0, co)
	end
	return instances[co]
end

Not sure if this would cause issues elsewhere, but it seems to work on first test.

@britzl
Copy link
Owner
britzl commented May 30, 2021

Where do coroutines get run in order of execution?

Coroutines are part of the Lua programming language. Lua is single threaded and there is only ever one chunk of Lua code running at a time. It's either the code on the main thread or code inside a coroutine. You can coroutine.resume() to start/resume the code in a coroutine and use coroutine.yield() to stop execution of code in a coroutine and yield control back to the main thread. You can read more in the Lua manual at lua.org

I think frame delay may come from in the function create_or_get

Correct. I use a timer to repeatedly check the state of coroutines that are waiting for a certain condition to be true before resuming them. And when a Flow is created it's coroutine gets started/resumed when the timer triggers for the first time. It's easy to start the Flow immediately, and I'm not sure why I designed it in any other way... :-)

@brettmjohnson
Copy link
Author
brettmjohnson commented May 30, 2021

That makes sense on Lua's coroutines.

For Flow, do you think you'll change it to start immediately? No big deal if not. I can always update my own branch if I need to.

Thanks for your help!

@britzl britzl closed this as completed in 0db5c00 May 31, 2021
@britzl
Copy link
Owner
britzl commented May 31, 2021

Yep, changed it now. Will release a new version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants