11-11-2024 09:58 AM
The impetus for this question was a talk given by Jeff Kodosky, where he describes the String Processing example using Streams.
In the screengrab above, if the stream channel endpoints are removed and replaced with array controls and indicators, the example becomes your usual run of the mill dataflow, where each subVI executes in sequence. In such a scenario, it is clear what happens. Each subVI executes in sequence, once. And with each subVI call, there is an overhead associated with each call, unless the subVI is inlined. And if the subVIs themselves are in a for/while loop and called repeatedly, each iteration of the loop adds some amount of overhead.
My question is: In the above example with channels, each subVI receives the input piecemeal, and all of them run in parallel. But each subVI is now effectively "called" multiple times. So, once the first line of the text is read, it is sent to the next subVI. While it is being processed, the second line is read. Once the Grep Strings subVI finishes processing the first line, it receives the second line of text and runs again, and so on. It seems analogous to the Grep Strings subVI being in a FOR loop and getting called repeatedly. But in the example subVIs, each is set to be a preallocated clone, but not inlined. So would that not add overhead? Or does having channels somehow automatically inline the subVIs?
Basically, my question boils down to:
Solved! Go to Solution.
11-11-2024 12:22 PM
SubVIs with channel wires as inputs execute in dataflow order, ignoring the channel wires themselves. They are invoked only once when their inputs are available. There's no "multiple call overhead" because there are no multiple calls. No special needs for reentrancy/inlining/etc. Each of the loops inside the subVIs runs in parallel, continuously invoking the endpoint subVIs.
If a subVI with a channel wire is non-reentrant, that means only one copy of the subVI is running at once across many different call sites -- exactly the same meaning as non-reentrant always means. If it is (either type of) reentrant, that means that multiple call sites can proceed in parallel.
11-11-2024 12:26 PM
Going a bit further -- if you mentally replace the channel wire with array wire, you do not think of the main subVI as being wrapped in a For Loop... instead, you think of the endpoint nodes as being replaced with Index Array and Build Array (respectively).
11-11-2024 12:35 PM - edited 11-11-2024 12:36 PM
Yes, but in that case, the data doesn't arrive piecemeal into each subVI, right? You get all of the array data all at once.
So just to be clear, if I have a series of subVIs connected with channel wires as shown above, in the beginning, only the first subVI gets executed (because it waits for the file path [dataflow dependency]) and stays in memory, and once it reads the first line, the second subVI gets called, and stays in memory, and so on...
And once the last line is read, the first subVI terminates, then the next subVI, and so on.
11-11-2024 12:42 PM
> Yes, but in that case, the data doesn't arrive piecemeal into each subVI, right? You get all of the array data all at once.
Yes. That's the point of Jeff K's thought experiment -- to understand how the channel wires are the same functionality with different timing.
11-11-2024 12:47 PM
@KVR9 wrote:So just to be clear, if I have a series of subVIs connected with channel wires as shown above, in the beginning, only the first subVI gets executed (because it waits for the file path [dataflow dependency]) and stays in memory, and once it reads the first line, the second subVI gets called, and stays in memory, and so on...
Actually, no. Pretend the subVIs are labeled 1, 2, 3, 4, 5, and 6. Because they have zero dataflow dependencies, subVIs 3, 4, 5, and 6 start running immediately. SubVI 2 will start running as soon as the string is available. SubVI 1 will start running as soon as the path is available.
SubVIs 3, 4, 5, and 6 will both do whatever initial work is inside of them up until the moment they start waiting on data from the channel wire -- in the case of 3/4/5, that's the endpoint node. Since 6 *is* an endpoint node, it's whatever setup work endpoint nodes do when they're first called.
To put it another way: If you were to put a One Button Alert in subVI 3 outside of both of its While Loops, that alert would appear as soon as you hit run on the main diagram.
11-11-2024 01:15 PM - edited 11-11-2024 01:16 PM
To put it another way: If you were to put a One Button Alert in subVI 3 outside of both of its While Loops, that alert would appear as soon as you hit run on the main diagram.
That clarifies it.
And the reason for the no overhead is that all of those subVis stay in memory and do not "offload" as long as the channels are open.
One thought experiment based on this:
If a subVI with a channel wire is non-reentrant, that means only one copy of the subVI is running at once across many different call sites -- exactly the same meaning as non-reentrant always means. If it is (either type of) reentrant, that means that multiple call sites can proceed in parallel.
In the diagram above, if I replace 3,4,5,6 with just 3 (that is, the above diagram is 1,2,3,3,3,3), and 3 is configured to be non-reentrant, the dataflow becomes sequential? Because only one instance of 3 can run at one time?
11-12-2024 12:25 AM
> In the diagram above, if I replace 3,4,5,6 with just 3 (that is, the above diagram is 1,2,3,3,3,3),
> and 3 is configured to be non-reentrant, the dataflow becomes sequential? Because only one
> instance of 3 can run at one time?
Is that what happens with any other non-reentrant subVI that you drop multiple parallel copies of? No. So the answer is still "no" when a channel wire gets involved. Just mentally delete the channel wire and analyze the dataflow dependencies...
Can you picture it? Let's see if you're right... here's the answer:
With 1,2,3,3,3,3, all the 3s start attempting to run at the same time because none have any dataflow dependencies. One of them at random starts running first. When it finishes, the next -- at random -- will start running next. And so on. If it happens that the order chosen is "first 3, second 3, third 3, fourth 3" then the program will run to completion assuming 1 and 2 eventually send a stop signal. But if any other order occurs, the program just hangs filling up one of the channel buffers.
11-12-2024 01:51 AM
@AristosQueue wrote:Can you picture it?
@AristosQueue wrote:Just mentally delete the channel wire and analyze the dataflow dependencies...
That is a very neat way to visualize it. Somehow missed this line on my first read. But when I did mentally delete the channels and mapped out the order of execution, I did arrive at the same answer. Going forward, that will be very helpful in analyzing and understanding diagrams with channels. Thank you, @AristosQueue!
Also, note to self: Set VIs with channels as reentrant if there is a chance they are going to be used in different places in the code (or just set them as reentrant to be safe). If they are just being used at one place, it is OK even if I forget to do so.