Now that you’ve seen how events travel through individual nodes, let’s look at the bigger picture: how they travel through a composition.
This section is about Vuo's mechanisms for control flow and concurrency.
Each event travels through a composition following a simple set of rules:
An event travels forward through cables and nodes. Along each cable, it travels from the output port to the input port. Within each node, it travels from the input ports to the output ports (unless it’s blocked). An event never travels backward or skips around.
One event can’t overtake another. If multiple events are traveling through the same cables and nodes, they stay in order.
An event can split. If there are multiple cables coming out of a trigger port or other output ports, then the event travels through each cable simultaneously.
An event can rejoin. If the event has previously split and gone down multiple paths of nodes and cables, and those paths meet with multiple cables going into one node, then the split event rejoins at that node. The node waits for all pieces of the split event to arrive before it executes.
An event can be blocked. If the event hits an event wall or door on an input port, then although it will cause the node to execute, it may not transmit through the node.
An event can travel through each cable at most once. If a composition could allow an event to travel through the same cable more than once, then the composition is not allowed to run. It has an infinite feedback loop error.
Let’s look at how those those rules apply to some actual compositions.
The simplest event flow in a composition is through a straight line of nodes, like the composition below.
In this composition, the Fired at Time trigger port fires an event every 10 seconds. Each event travels along cables and through the Count node, then the integer-to-text type converter node, then Display Console Window node. The event is never split or blocked.
When you run a composition in Vuo, multiple nodes can execute at the same time. This takes advantage of your multicore processor to make your composition run faster.
In this composition, the two Count nodes are independent of each other, so it’s OK for them to execute at the same time. When the Fire Periodically node fires an event, the upper Count node might execute before the lower one, or the lower one might execute before the upper one, or they might execute at the same time. It doesn’t matter! What matters is that the Add node waits for input from both of the Count nodes before it executes.
The Add node executes just once each time Fire Periodically fires an event. The event branches off to the Count nodes and joins up again at Add.
In this composition, the Add node executes each time either Fire Periodically node fires an event. If one of the Add node’s inputs receives an event, it doesn’t wait for the other input. It goes ahead and executes.
If the two Fire Periodically nodes fire an event at nearly the same time, then the Count nodes can execute in either order or at the same time. But once the first event reaches the Add node, the second event is not allowed to overtake it. (Otherwise, the second event could overwrite the data on the cable from Add to Display Console Window before the first event has a chance to reach Display Console Window.) The second event can’t execute Add or Display Console Window until the first event is finished.
Compare this composition to the one above it. Since in this composition the Fire Periodically nodes can execute in either order, or at the same time, the results are unpredictable. When you want to ensure events are executed by separate nodes at the same time, use the same event.
You can use a feedback loop to store and build upon a result over time. This example composition demonstrates ( ):
Starting with the image from Fetch Image, this composition adds another twirl to the image with each display refresh. Over time, the entire image accumulates twirls upon twirls.
The orange and gray nodes, and the cables between them, comprise the feedback loop. Let’s focus on the part of the loop that stores and repeatedly processes the image: Hold Value, Select Latest, and Twirl Image. Each time Fire on Display Refresh fires an event:
The event enters the Hold Value node’s Update input port.
The Hold Value node executes, outputting the event plus the image produced the previous time around the loop (or an empty image if this is the first time around).
The event plus image enters the Select Latest node’s Option 2 input port.
The Select Latest node executes, outputting the event plus the image from Hold Value (or the original image from Fetch Image if this is the first time around).
The event plus image enters the Twirl Image node’s Image input port.
The Twirl Image node executes, outputting the event plus an image with one additional twirl.
The event plus image hits the Hold Value node’s Value input port.
The Hold Value node executes, although it doesn’t have any visible effect. It doesn’t output any event or data because the event is blocked at the input port’s event wall.
With each event fired from Fire on Display Refresh, these steps repeat and the image gains another twirl.
For each event from Fire on Display Refresh, when exactly does the Hold Value node output an image to Render Image to Window? The first time Hold Value executes, the second time, or both times? The answer is: Only the first time.
The first time Hold Value executes:
The event hits the Update input port.
The node executes.
The event plus data travels out of the output port through all connected cables, including the one to Render Image to Window.
The second time Hold Value executes:
The event hits the Value input port.
The node executes.
Nothing further happens. The event is blocked by the wall on the input port.
You can control how your composition executes by controlling the flow of events. The way that you connect nodes with cables — whether in a straight line, a feedback loop, or branching off in different directions — controls the order in which nodes execute. The way that you fire and block events — with trigger ports and with event walls and doors — controls when different parts of your composition will execute.
Each event that’s fired from a trigger port has its own unique identity. The event can branch off along different paths, and those paths can join up again at a node downstream. When the same event joins up, the joining node will wait for the event to travel along all incoming paths and then execute just once. But if two different events come into a node, the node will execute twice. So if you want to make sure that different parts of your composition are exactly in sync, make sure they’re using the same event.