-
Notifications
You must be signed in to change notification settings - Fork 28
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
Match Scratch's script sequencing and execution semantics #212
Comments
Out of curiosity... busy waiting is (unfortunately) a thing in Scratch, right? The easiest tell is that just clicking a "forever" block will cause dragging around blocks in the editor to suddenly feel choppy and slow. Can you narrow down on which circumstances of busy waiting we wish to avoid, and/or define busy waiting more particularly? Although we want to match Scratch's project behavior i.e. all execution semantics, we can (and do) differ in the implementation that "gets us there". This may be able to include avoiding certain instances of busy-waiting, but we have to be sure that the definition of busy-waiting is separate from the definition of runtime semantics. The presence or absence of any busy-wait we remove shouldn't affect project semantics. |
Yes, there are still situations where Scratch will busy wait--as you mentioned, an empty "forever" block with nothing to request a redraw will do so, and I believe a "wait" block will do so as well in the absence of any redraw requests. Scratch will not busy-wait on promises, however--threads have their own "promise wait" state that causes them to be skipped over until the promise resolves. Any thread that is itself waiting for one of those threads to finish will need to do the same--see scratchfoundation/scratch-vm#1211, for instance. |
While we're discussing promises, this feels like a good time to reference the discussion about triggers: #197 I'm not very happy with the user-facing API for triggers, and it feels like an |
I actually don't think we need async functions or generators--I'm working on an experimental runtime revamp that allows you to simply EDIT: For instance, this is how public *askAndWait(question: string): Yielding<void> {
yield* Thread.await(this._project.askAndWait(question));
} |
Oh, nice! (I believe yielding a promise is equivalent to an async generator, but I'm not 100% sure.) |
It looks like the difference is that an async generator always yields promises, whereas a regular generator only yields promises if the thing being yielded is already a promise. |
Right now, Leopard's execution semantics seem to be rather simple--we step each script once per frame. This is close enough to what Scratch does in many cases, but in actuality it's a bit more complex. Scratch's logic is roughly:
Scratch also supports "turbo mode" semantics, which fit neatly into the above logic: if turbo mode is enabled, then we don't stop when a redraw is requested, only caring about the other two conditions (scripts are done, or time budget).
The main pitfall to watch out for when implementing this is busy-waiting. Right now, there's a lot of code that
yield
s in a loop while waiting for a promise to resolve. This is fine if we only step threads once per frame, but in the case where no redraws have been requested or we're running in turbo mode, those loops will gladly spin until we've used our time budget, eating up a bunch of CPU time.To avoid busy-waiting, I believe we need runtime support for yielding to promises--a script waiting for a promise is placed into a "sleeping" state where it will not be stepped until the promise resolves.
The text was updated successfully, but these errors were encountered: