相同事件的启动顺序

Scratch中的指令有4种执行方式,顺序执行循环执行条件分支并行执行。其中并行执行就像是角色拥有了分身术,可以利用多个指令串,同时完成多个任务。

现在我想请你思考一个问题,多个指令串在并行执行时,角色真的是在同时执行多个指令吗?如果不是同时的,它们又是按照什么规则在执行呢?

要回答上面的问题,你可以从一个小实验开始。

打开Scratch,先将小猫移动到舞台的正中央。

接下来请你为小猫添加下图中的两个指令串。

现在请你想一想,点击绿旗按钮以后,小猫说话的内容是0还是100?

类似的操作,再添加一个蝙蝠角色。然后先将小猫移到(x:-100,y:0)位置,蝙蝠移到(x:100,y:0)位置。

接着分别给它们添加一个指令串,让小猫说出蝙蝠的y坐标,让蝙蝠移到(x:100,y:100)的坐标位置。

现在请你想一想,点击绿旗按钮以后,小猫说话的内容是0还是100?

执行完上面两个实验,你还可以继续增加难度,给小猫和蝙蝠分别添加对方的指令串。

现在,点击绿旗按钮以后,小猫和蝙蝠分别会说0还是100?

假如你是和几个朋友分别在各自的电脑上来完成以上的实验,你会发现,很可能你们试验得出的结果并不相同。也就是说,你们所有人指令执行的顺序好像是随机的。

可是,如果你多次重复自己电脑上的实验,你又会发现,很可能你每次得到的结果又是相同的。也就是说,你电脑上的指令执行顺序好像是固定的。

一边是随机,一边又是固定,到底哪个才是正确的?如果固定是正确的,它们的执行顺序又由哪些因素决定呢?

如果你学习过高级编程语言,你可能听说过一个名字,线程open in new window

线程的执行类似于Scratch中的并行事件,一个线程就是一个指令串,多个不同的线程并发执行时,就“同时”完成了多个任务。我把“同时”两个字加上引号,是因为它们并不是真正的同时执行,而是由操作系统或是编程语言本身所控制。

实际的执行过程中总是只有一个线程被执行,只是多个线程之间会快速的进行切换,从而造成了一种有多个线程被“同时”执行的假象*(如果你使用的是有多CPU的电脑,当多个线程被分配到不同的CPU上执行时,可以实现真正的并行)*。

你现在所使用的Scratch 3,它是使用一种名叫 JavaScript 的高级编程语言所开发。这种编程语言主要用于你每天在浏览器中所看见的网页。网页就类似于Scratch中的舞台,为了保证网页中的内容能够正常显示,JavaScript只启用了一个主线程来执行程序,再通过加入事件机制和Web Work这类的方法,从而实现了类似于多线程并发的效果。

在Scratch 3中也采用了类似的实现方法。你可以在脑子中想象一个画面。每当一个帽子形状积木(事件分类积木和当作为克隆体启动时积木)的条件被满足时,它就会被加入一个由Scratch控制的执行队列中。接着,它们就像你在生活中排队办理业务一样,按照Scratch所制定的某种规则,依次被执行。

回到之前的三个小实验,我们现在就一起来找出Scratch制定的指令执行规则。看看当你点击绿旗按钮以后,被加入执行队列的这几个当绿旗被点击事件,会按照什么样的顺序被执行?

首先来看看第一个实验。

同一个角色,拥有多个相同事件时,它们的启动顺序由什么决定?

答案是,由你编程区中事件积木被拖入的先后顺序所决定。先被拖入编程区的事件积木先启动。

现在重新在舞台上只留下一个小猫,将它移回舞台中央。

接着,拖入三个当绿旗被点击积木,将它们按照拖入编程区的顺序,从上到下依次排列。

接下来,将之前实验中的说(你好!)积木和移到x:(0) y:(0)积木放在任意两个不同的事件积木下面,点击绿旗按钮,验证一下我的说法是否正确。

如果说(你好!)积木放在移到x:(0) y:(0)积木的前面,就会先执行说(你好!)积木。小猫将先说出当前的x坐标0,再移到(x:100,y:0)的位置,包括以下三种情形。

如果移到x:(0) y:(0)积木放在说(你好!)积木的前面,就会先执行移到x:(0) y:(0)积木。小猫将先移到(x:100,y:0)的位置,再说出此时的x坐标100,包括以下三种情形。

或许你会想,有没有可能执行顺序并不是由拖入的事件积木顺序,而是由积木的位置所决定?

例如,放在上面的积木比下面的积木先执行,或者放在左边的积木比右边的积木先执行。想知道你的假设是否正确,就要学会自己设计实验,接着去动手验证它。

解决了第一个实验的困惑,接下来轮到第二个实验。

不同角色,拥有多个相同事件时,它们的启动顺序由什么决定?

答案是,由角色之间的层级顺序所决定。多个角色间,位于层级靠前的角色中的事件积木先启动,位于舞台中的事件积木最后启动。

同样的,重新把舞台上的小猫和蝙蝠放回各自的初始位置。再给它们添加与之前实验相同的积木。

接下来在点击绿旗按钮之前,你需要先利用移到最[前面]积木来调整小猫或者蝙蝠的层级。

例如,你可以控制小猫。点击一次移到最[前面]积木,让小猫先移到层级的最前面。接着点击绿旗按钮,小猫的说(你好!)积木会先执行,说出蝙蝠当前的y坐标0。然后蝙蝠执行移到x:(0) y:(0)积木,将自己移到(x:100,y:100)坐标位置。

接下来,将蝙蝠移回初始位置。这一次先点击移到最[后面]积木,让小猫先移到层级的最后面。接着点击绿旗按钮,蝙蝠的移到x:(0) y:(0)积木会先执行,将它移到(x:100,y:100)坐标位置。最后小猫的说话积木才会执行,说出蝙蝠当前的y坐标100。

为了更全面的验证我上面的说法是否正确,你还可以继续增加第三个角色,或者给舞台增加指令进行验证。

最后,在第三个实验中,是将前两个实验的规则进行了融合。

先按照多个角色的规则,确定好角色的启动顺序。再按照一个角色的规则,启动角色中的多个事件积木

具体的验证工作,就留给你自己来完成了。

利用上面的实验,你已经找到了影响相同事件积木启动顺序的因素,请继续往下思考。上面的实验中,所有事件积木后面都只拼接了一个指令积木,假如改为拼接多个指令,它们又会按照什么顺序来执行呢?请你先自己提出假设,再动手设计实验去验证它。

最后,我还想提醒你一个注意事项。虽然现在你已经知道了影响相同事件积木启动顺序的因素,但是在实际的开发过程中,你很容易就会忽略掉它们。如果你将自己的程序分享出去给别人修改的话,他们就更不可能知道每个事件积木的启动顺序是什么样。

因此,你在实际开发的过程中,应该假设事件积木的执行顺序是随机的,以此作为前提进行开发。假如你有一个功能确实需要对几个指令串的执行顺序进行控制,除了上面提到的影响因素之外,还有别的方法可以实现它。

Last Updated:
Contributors: lanheixingkong