Here's a newbe perspective from a programmer who has not thought about FPB in a while.
It seems that there is an implicit flow on information back through the network. Let's say final node want's to update it's display X times a second. After composing and displaying the image it signals that it can accept new inputs. This flows back through the network to the producer nodes at the beginning of the network. These guy's produce fresh data the flows forward through the network. That way no one is actually doing any computation until it is needed.
Interesting idea, David. However, in the FBP context, I think you are either introducing a second network of essentially zero-capacity connections, or you are sacrificing configurability (if A and B both "know about" C, without going through the network). JavaFBP does have a component priority facility, which might be worth trying out. People have suggested adding a priority attribute to the IPs (queue-jumpers), but IMO that makes the application as a whole less reliable.
Either way, IMO it is much simpler to do what I suggested earlier - did you try it, Forrest? - which is to feed multiple output ports into a single input port. If you want really fast response, you can use a connection of capacity 1. If you want better than that, I suspect you are going to have to build your own scheduler!
I assume you have a process receiving inputs (IPs) at multiple input ports. If 2 or more inputs arrive at different input ports at the same time (?), you want to process - just one, or neither?
On Saturday, July 28, 2012 11:57:39 AM UTC-4, dmbarbour wrote:Hello Forrest,A simple, effective solution is to add a "touch" event to each dataflow. When you know an update is coming soon, you send a touch event. Touches propagate through the network independently of the primary data updates.For linear dataflows, the touches are a simple propagation (see a touch? send a touch). For dataflows that receive updates from multiple sources, e.g. A & B -> C: we send a touch on C the first time we see a touch on A or B. If B is touched, and we receive an update on A (or vice versa), we wait to propagate. For dataflows that send updates to multiple sources, e.g. A -> B & C, we might touch to both B&C after receiving touch on A.We might also introduce a "cancel" message to account for those cases when we've touched but decide (due to filtering or splitting) that we don't need to update a given task. The important bit is that we always send an update at some point after sending a touch. The idea can be modified easily with features like counting, indicating how many updates are coming, etc.Managing these touches has an overhead proportional to the size of the network (though you can introduce barriers or model partitions across which touches are dropped). But the costs are small, predictable - and the win can be enormous, eliminating worst-case exponential costs in networks that merge many data sources.Regards,David Barbour
I believe you misunderstood the problem Forrest is attempting to solve. You earlier wrote:
I assume you have a process receiving inputs (IPs) at multiple input ports. If 2 or more inputs arrive at different input ports at the same time (?), you want to process - just one, or neither?
Forrest wants to process both inputs, but wants to process them together (rather than one at a time). E.g. if the time on the clock and the color of the clock change at approximately the same time, we would want to send only one "Render" IP that addresses change in both color and clock, as opposed to sending two "Render" IPs in short succession.
I stumbled upon this FBP group not really understanding the distinction between FBP, reactive, and other paradigms... I know enough to be dangerous, but I'm learning.
I am trying to understand the touch concept and pseudocode. In the clock example, what sends the touch and how does it flow through the graph?
Also, thinking about clocks, it would make sense to process the image for the next second. Then in the output you should show the processed image much closer to the actual second tick.
Dave,
This touch idea sounds similar to the null convention logic described in "Computer Science Reconsidered" by Karl Fant.
In a nutshell the null convention logic is used to implement a "clock-less" system i.e. rather than relying on a central clock
to synchronize the processing of multiple inputs into a logic gate, a null state (yeah, a third state, besides the 0 and 1 state)
is emitted by the logic gate to indicate the "ready-ness" of the logic gate output.
Matt
Add a feedback loop to the refresh component. When the component finishes an update, it sends itself a blip and enters a waiting-for-blip-state.
In that state, it simply pulls update requests off of the queue (in order of arrival) and dumps them on the floor.
Once the blip arrives (advances to the front of the input queue), the component goes back to the process-updates state, wherein the next update request will cause a full update as above.
On Wednesday, August 1, 2012 12:38:17 PM UTC-4, paul.tarvydas wrote:
Add a feedback loop to the refresh component. When the component finishes an update, it sends itself a blip and enters a waiting-for-blip-state.
In that state, it simply pulls update requests off of the queue (in order of arrival) and dumps them on the floor.
Once the blip arrives (advances to the front of the input queue), the component goes back to the process-updates state, wherein the next update request will cause a full update as above.
Hi Paul,
That's a great suggestion! It does assume that the display component knows when it can accept another display request - if it does not know (i.e. it sends out the display refresh asynchronously), then I believe you have to use the clock idea I posted above. Either way works...
If I read your post correctly, it also sounds as if all your components just have a single input connection, and input ports (in my sense) are basically tags on incoming IPs. If I'm right, that certainly removes some of the concerns I run into, e.g. much of the potential for deadlocks, but I would think there are some functions that become more difficult, e.g. how would you handle Collate? OTOH I may have misunderstood...?
You and I probably have different mental models of what constitutes an IP - mine are particles, yours are waves (streams).
In my mental model, the inputs A and B to Collate are blips (single records, say). To collate an A with a B, you have a three-state state machine: 10. wait for either an A or a B, 11. got an A, wait for B, 12. got a B, wait for A. 11 and 12 transition back to 10 and during the transitions they "collate" the A with the B and send it to the output port.
On 06/08/2012 3:08 PM, Paul Tarvydas wrote:
You and I probably have different mental models of what constitutes an IP - mine are particles, yours are waves (streams).
I think my IPs are particles too...
...I have to say that I don't have the concept of "waiting for A" - I just receive IPs from a connection (input port), and see what kind each one is. For Collate, this forces me to have multiple input ports, as Collate checks the control fields on every IP, comparing the first (oldest) IP from each input stream, emitting the "low" IP, and then refreshing the IP from that input port. Let's say I have a million A's, and 10 B's, I have to start by comparing the control fields of the first A and the first B, but I can't "read ahead" through the million As to find the first B. So I guess I find I don't really understand the mental model you are describing...
Oddly enough the use of Collate is described in Chap.9 (Chap. 9 again!).
If I understand your concern, maybe you were orienting on the parser part of the logic only, rather than on the merge part of the function. The JavaFBP Collate has one array input port, so it can merge any number of streams together based on up to 99 control fields IIRC, and of course inserts delimiter IPs into the merged stream.
Hth
Paul
Paul Tarvydas <paul.t...@rogers.com> wrote:
>On 12-08-06 10:06 PM, Paul Morrison wrote:
>> ...I have to say that I don't have the concept of "waiting for A" - I
>> just receive IPs from a connection (input port), and see what kind
>> each one is. For Collate, this forces me to have multiple input
>> ports, as Collate checks the control fields on /every/ IP, comparing
>> the first (oldest) IP from each input stream, emitting the "low" IP,
>> and then refreshing the IP from that input port. Let's say I have a
>> million A's, and 10 B's, I have to start by comparing the control
>> fields of the first A and the first B, but I can't "read ahead"
>> through the million As to find the first B. So I guess I find I don't
>> really understand the mental model you are describing...
>>
>
>I don't understand. We must be miscommunicating, or, I am ignorant of
>some nuance of the Collate problem (not a problem I've often worked on).
>
>Ch. 9 appears to show the idea of what I would call a "parser" - it
>inserts "tokens" (control fields) into the stream to help the downstream
>processing. Compiler courses at U of T teach this method as a way of
>eschewing the use of (all in-core) parse trees.
>
>The code in Ch. 9 shows what I would call a one-state state machine -
>each transition is triggered by an IP type, then each transition simply
>goes back to the top.
>
>I don't see why what I've described cannot do this, also (unless the
>description is poor :-)...
>
>> Oddly enough the use of Collate is described in Chap.9 (Chap. 9 /again/!).
JSD uses messages known as time grain markers which act like data streams but which contain timing information. They are rough-merged with other data streams to control the arrival of messages and the timing of the execution of processes. They are used to trigger actions within processes, start and stop processes and generally aid the synchronisation of processes.
I'm working (slowly, in spare time) on a solution to the "collision" problem using FBP components and etherons...
the Time Grain Marker used in JSD:
JSD uses messages known as time grain markers which act like data streams but which contain timing information. They are rough-merged with other data streams to control the arrival of messages and the timing of the execution of processes. They are used to trigger actions within processes, start and stop processes and generally aid the synchronisation of processes.
As with FBP JSD has just one input to a process upon which different types of message are placed.
Here is my latest Meemoo creation: http://meemoo.org/iframework/#example/rainbowclock
I have run across a funny issue in coding more complex images like this. In most of the modules, I want every input to potentially trigger a calculation (and output). But if several inputs change at the same time, I don't want to .
My solution was to put a 1000/30 ms timeout on every input. If more inputs are hit in that short timespan, the timeout is cleared. Example with the string-join.html module: https://github.com/forresto/meemoo-modules/blob/gh-pages/string-join.html#L36
This isn't optimal, because each module is now slowing down the data-flow. You can also see that in 14:transform, the image is rendered twice per second anyway, as the rotate input is hit before the image from 5:text makes it (because 7:string-join and 5:text modules have the timeout as well).
Pure Data uses "hot" inputs. I could do something like this that would only send the data when a "send" input is hit, but that would make for more complicated graphs.
Is there a better or standard data-flow way to solve this?
- Forrest
OK, so after reading the code for Collate, I think I see some points of miscommunication that are "too obvious" to each of us.
My components have multiple inputs and multiple outputs.
(The inner "funnel" queue is how I remove the need for preemptive multi-processing. Ignore that for now.)
The main "obvious" non-stated point is, I *think*, that your ports operate in a "pull" manner, whereas my ports are "push".
My code is reactive. When an input arrives, it reacts to it.
It can not (inherently) control "when" an input arrives.
I *think* that the Collate problem you describe can be paraphrased as: Collate has two inputs A and B.
One A arrives, followed by a million B's.
Your solution to Collate requires that only one A and one B are held in the Collate component at a time.
Your "pull" ports (automagically) regulate the influx of B's, pulling only one at a time, processing it, then pulling another.
My "push" ports *appear* to have the drawback that they can't regulate the influx of B's.
In a dumb solution, a million B's would pile up in the (hidden) input queue.
The solution is to think reactively - use a (network-like) protocol.
I *can* regulate the influx of B's by sending an upstream request for each B. The response to the request is one B, or, EOF.
(Same for the A port).
So, I have two input pins A and B, and two (output) request pins ReqA and ReqB going upstream.
In the domains where I've worked, e.g. embedded, reactive systems, it makes much more sense to have as much asynchronous parallelism as possible.
The convenience overrides the slight inconvenience of having to add a REQ/ACK protocol when you want to synchronize.
And, frankly, I like the idea that the Architect/Engineer has to Engineer synchronization, explicitly (visually), into the solution.
That's, also, why I talk about state machines, whereas you talk about case statements and loopers. (Reactive programming needs to track state, state appears to be moderately implicit in the sequential code of the pull model).
OTOH, if, 20 years ago I'd been forced to process bank records instead of monitoring hardware sensors, then maybe I would have made my ports "pull", also :-).
This raises an interesting question(s).
Are there two kinds of FBP? Push vs. pull?
Should (the Grand Unified) FBP support both, push and pull, ports?
[Oh, and then we can argue about multi-drop output ports and the required semantics - also, quite useful in the reactive space. I feel a lunch coming on :-].
Assuming, that is, that I've finally understood and have paraphrased your problem correctly :-).
pt
So, is FBP "push" or "pull"? I don't know, and I really don't feel it matters! Sorry, Dan!
Now I begin to see why multiple input ports on a single process are a problem (for several of the people participating in this discussion, apparently): since code gets executed immediately on the arrival of IPs, then it matters a lot in what sequence they arrive.
Parenthetically, my JavaFBP VolumeTest executes 100,000,000 sends and 100,000,000 receives in 4 mins. on my 4-processor desktop, and keeps all processors 99% busy!
Maybe FBP should come in two major flavours - reactive and thread-oriented...? Like iterative vs. recursive...? Probably a bad example..
Parenthetically, my JavaFBP VolumeTest executes 100,000,000 sends and 100,000,000 receives in 4 mins. on my 4-processor desktop, and keeps all processors 99% busy!
That seems quite poor for performance, even in Java. I.e. you're breaking it down to 420k IPs per second, even after buffering. Granted, I don't know the quality of your processors, the nature of the benchmark, or the size of your bounded buffers. But Erlang, Akka, AsyncFP, etc. tend to benchmark in millions of messages per second.
> Let FBP be FBP, and let reactive be reactive,
If FBP is "push", but not reactive, what is the difference between push and reactive?
I am using a variant that has 0-length bounded buffers (i.e., the wires are "stupid" and cannot tell the upstream to slow down).
I agree with PaulM that the architecture (diagram) should not be altered at runtime.
Paul M.: “Sorry, Dan (again). I feel there is something going on here that I am not grasping!”
I am afraid so :-).
“Pull” and “push” are a way to implement two different aspects in FBP. Strictly speaking everything is “push” but for various reasons “pull” is the only way to implement the situation I have described for “potential” connections where I want the same value (content of a component) in different places at the same time.
A->B means B is continually connected with A and each time A is changing B is following A instantly. B has the same value with A all the time. I don't know when to push the value of A into B, because I have to do it all the time. So what am I doing? I do nothing. I will “pull” A into B only at demand. This is lazy programming. Demand is created in the downstream (i.e. at B). Now you can imagine A and B with multiple ports and the connection is A.o1 -> B.i1. Demand is created in B as a result of an IP that is coming into B through another port e.g B.i2.
A “function call” is an instance of a model (function). The model is at runtime! Its value is the function code (compiled). The instance (“function call”) is connected to the model with a “potential” connection. The model could contain data too. Data could be part of a model. Also data mixed with functions could be part of a model. It does not matter, the logic remains the same.
Paul M.: “For me, Sin and Cos have *nothing* to do with push or pull :-)
I probably wouldn't use an FBP component for Sin or Cos as these subroutines (methods) are already black-boxy and synchronous[...]”
Even if we can find versions of Sin and Cos already made and packed as subroutines in C++, Java or whatever else, it does not mean that a FBP style of Sin and Cos will not do. FBP is not just coordination language. Sin and Cos were used as examples. You can name them as you want and imagine they are complex functions written fully in “FBP style” all the way down to the atomic components.
When building a FBP program why to stop to a certain granularity? Why not going to the finest granularity? Why not having a full FBP compiler and language? Why to be obliged to use Java, C, C++ or other language for the lower granularity components?
My example was not in the context of a FBP middleware that has subcomponents implemented in another language. This is good to have and must to have but not this is the issue. I was talking about a full FBP environment. Such a platform is stackless or it works with stacks but not in the form we know from the imperative programming.
Paul M.: “If this is acceptable, then the *component" is Sin, and the multiple occurrences are "processes", each with its own thread of control[...]”
Not necessarily. In a compiled version of the component, Sin will not be a process with its own thread of control but it could be. Obviously this is not necessary but it does not mean automatically that my FBP style of Sin is a function that uses the same calling protocol as in imperative languages (using standard calling stack mechanism). This is the main issue I was discussing about.
Paul M.: “I get the feeling that you may be thinking of a more complex case, where you want to be able to load component code at run time.”
Yes, I do. Even if this is not the case, the logic has to deal with this aspect. For instance, the compiler has to build code for loading the component at runtime. The largest component loaded is the entire program that has to run. Why not being able to load at demand the components at runtime?
Paul M.: “Still, I really don't see what this all has to do with push or pull. :-)”
It has because you pull the component that is loaded. The frozen component from the hard disk will not have any "initiative" to load by itself in the memory. It is dead. Another component will have the initiative.
Brad Cox: “Perhaps std OO terminology might help? Sin(model) isn't a component, but a component *class*. Sin1 and Sin2 are components; i.e. *instances* of a component class.”
This is totally wrong. I think this misconception is widely spread. Sin(model) is a component (instance) and not just a component class that usually it is associated with the source code (text). A model could be instance in the same time. You are used with the terms from C++: something is an instance of a class. So a class is not an instance. In C++ this is true by definition. In my case it is not. A model is a class and can be an instance. The class is another form of an instance of type singleton. I know, it's difficult to grasp :-). Between the class/model (that exists as source code) and the runtime model (as instance) is a relationship. One it is transformed into another by a compiler. Just the underlying base is changed; essentially the information is the same.
Maybe I will treat this in detail into a another topic but I will give you a short example here. Let's suppose we are developing a game with ships, cars, characters and a lot of other entities. We have more ships of the same kind. A model of a ship is not designed entirely in code (e.g. C++). It contains code and data altogether. I need more replicas of this object in my game. How am I doing that? If you ask the computer game programmers they will answer you that they are designing behavior and data partially in C++ (with classes), partially in scripts, partially in data files. Scripts are used to make the code developing easier for non-programmers but also to “configure” complex constructs that contains code and data (the ship itself). In the end they will have a real component at runtime (i.e. an instance) that is used as a model. This model (template) is cloned. The cloning process could be very complex (unfortunately) because it could contains logic of what is really duplicated and what is used in common (common data from the model that is referred in the instance). Besides that, the cloning has to deal with the different context (i.e. connections).
Brad Cox: “Instances may have state (not relevant for sin/cos, but yes for average or wordCount) and can thus differ from other instances even though sharing the same class.”
Instances can have state and also the model can have state. Including our functions sin and cos may have state. Imagine the sin and cos calculated using tables and interpolation method. They have state (that in this case is not modified but shared).
The problem is that you see a “class” at compile time as text code and an instance at runtime as bytes. In general terms a model is a class (text source code) and it could be an instance (template at runtime to clone). There is no fundamental difference but the form of existence. Of course the instance (at runtime) is prepared (compiled) for a certain type of microprocessor.
Brad Cox: “Afraid I still can't get away from the feeling that conveyor belts that can haul power and/or materials is a bad idea.”
Paul M.: “And I agree about the last sentence too! Power and materials have totally different behaviour!”
I don't get it. The conveyor belt is used as a metaphor. What's wrong with that? Somebody has to be in charge with transportation of the IP from one place to another. This is just the logic because it does not happen like this in reality. All the time in reality the transportation of data from one place to another is through a copy process. Nothing moves effectively and if the entire program runs on the same computer that data is not moving at all. It is copied (fetched) in the microprocessor, interpreted, executed and saved back in the memory but nothing really moves. Conveyor belt remains a metaphor.
Paul Tarvydas: “If FBP is "push", but not reactive, what is the difference between push and reactive?”
Yes, I have the same question too. I don't see the difference.
Paul Tarvydas: “And, fwiw, I do think of the flow as "electronic", but not based on potential - based on narrow pulses (pulse trains) instead.”
In order to eliminate any confusion, if you think of the flow as based on pulses then it is about “push”. When I was explaining the “potential” type of connection it was “pull” (the initiative belongs to a downstream component). “Potential” type of connection brings an information from one place to another but the receiver can not modify it in any way without producing a short circuit. It is read only. It is like the emitter applies a potential to the “wire” and on the other end the receptor tries to apply a different potential.
Paul Tarvydas: “I agree with PaulM that the architecture (diagram) should not be altered at runtime.”
I completely disagree. I do not understand why do you think a program should be static. I am bringing again the example of computer games because they are so dynamic. What is static there? Everything can change and dynamically interconnect or disconnect. It is mandatory to be dynamic. How to deal with static networks as long as the game application itself is dynamic. Maybe you can explain to me how you can create a complex computer game application without having a dynamic network. What you try to simulate in the game is dynamic by definition. The game application could be quite different from a business application.
Regards,
Dan
Let's suppose we are developing a game with ships, cars, characters and a lot of other entities. We have more ships of the same kind. A model of a ship is not designed entirely in code (e.g. C++). It contains code and data altogether. I need more replicas of this object in my game. How am I doing that? If you ask the computer game programmers they will answer you that they are designing behavior and data partially in C++ (with classes), partially in scripts, partially in data files. Scripts are used to make the code developing easier for non-programmers but also to “configure” complex constructs that contains code and data (the ship itself). In the end they will have a real component at runtime (i.e. an instance) that is used as a model. This model (template) is cloned. The cloning process could be very complex (unfortunately) because it could contains logic of what is really duplicated and what is used in common (common data from the model that is referred in the instance). Besides that, the cloning has to deal with the different context (i.e. connections).
...
> I agree with PaulM that the architecture (diagram) should not be altered at runtime.
I can think of many reasons to alter a diagram at runtime - e.g. to model extensions and plugins, linking, service
I completely disagree. I do not understand why do you think a program should be static. I am bringing again the
Concur, FBP as described by PM is undeniably both.
On Saturday, 11 August 2012 14:31:09 UTC-7, Paul Morrison wrote:On 11/08/2012 4:11 PM, John Cowan wrote:
> I would say it is pull on the input side and push on the output side.
That's my feeling too!
2. At first, we drilled down "too deep". A component for "+", "-", "!", etc. Amateur mistake.
5. We built diagram editors that "helped" you by doing type-checking at edit time. About as bad an (thankfully dead) idea as structured editors for textual code.
By my count, there's only a handful of people here who have used FBP for an extended period of time and have delivered non-toy production systems and have earned a living doing so.
I don't see any of them advocating dynamic modification of diagrams. Why?
Did you experience "self modifying code" back in the days of assembler? Was that a good idea?
> FBP language (if there is any) *is not functional*. Yes, sometimes lazy but
> not functional. FBP language is FBP. Components can have state.
*Components* can have state, yes. But the connection language,
mini-language, configuration language, whatever you want to call it,
doesn't have state.
Furthermore, it executes its components lazily.
David Barbour scripsit:
I repeat: my point is that the connection language is lazy and pure, not
> Isolating consideration to the connection language seems a bit odd,
that the FBP program as a whole is.
See Conal Elliott's squib "The C Language Is Purely Functional" at
> claiming that C is pure because semicolons have no side-effects.
<http://conal.net/blog/posts/the-c-language-is-purely-functional>.
At any rate, if Haskell is pure functional, so is C.
State only contaminates if you can see it.
Concurrent/serial is lazy/strict from a different standpoint.
We can define a (pure) function - advance - that takes graph G and state S - and returns the a new state S1 (or a new graph G1, in the dynamic case):
(G2,S2)=advance(G1,S1)
(G3,S3)=advance(G2,S2)
I would claim such thing to be purely functional.
Lazy or strict should not make a difference.
On Aug 13, 2012, at 11:44 PM, David Barbour wrote:
>
>
> On Mon, Aug 13, 2012 at 2:06 PM, John Cowan <co...@mercury.ccil.org> wrote:
> David Barbour scripsit:
>
> > Isolating consideration to the connection language seems a bit odd,
>
> I repeat: my point is that the connection language is lazy and pure, not
> that the FBP program as a whole is.
>
> Your point is also pointless and misleading in practice. You should consider not making it, rather than repeating it.
>
>
> > claiming that C is pure because semicolons have no side-effects.
>
> See Conal Elliott's squib "The C Language Is Purely Functional" at
> <http://conal.net/blog/posts/the-c-language-is-purely-functional>.
> At any rate, if Haskell is pure functional, so is C.
>
> In case you missed it, Conal was making a point of absurdity. Are you trying the same?
>
> Haskell models many excellent impure imperative languages - e.g. IO, ST, State, and various monad transformers built atop them.
>
>
> State only contaminates if you can see it.
>
> Yes. And, in FBP, state is observable.
>
>
> Concurrent/serial is lazy/strict from a different standpoint.
>
> No, it isn't.
>
> Regards,
>
> Dave
>
> --
> bringing s-words to a pen fight
If terms have a strict definition that resides in a shared vocabulary that we can consult then please let us know where we can find it.
If you have a clear idea of how you use some terms in your usual context then please recognise that words can have a different usage in other contexts.
Please say: "That is not how the term is used in my context of...."Please do not say: "Wrong. You sound really stupid trying to use grown up words you don't understand. "
On Tue, Aug 14, 2012 at 12:22 AM, Ged Byrne <ged....@gmail.com> wrote:If terms have a strict definition that resides in a shared vocabulary that we can consult then please let us know where we can find it.Push vs. Pull does not have a strict formal definition. The phrases do, however, have rich history in PL and program architectures, and correspondingly deep connotations. (Connotation is a good word for an important kind of informal meaning. I was careful to use it in my earlier discussions with you. Look it up someday.) I cannot educate you in connotations; only you can educate yourself and choose to respect that history and communicate.
The above benchmark involves pumping 100,000 IPs through 1,000 Copy processes in a "string of pearls" configuration. I ran another benchmark where I generate 100,000,000 IPs and simply send them to a Discard process - this took 20 mins. <blush>. Now, if my calculations are correct, this means that a send/receive pair takes 2.39 microsecs, but a create/drop pair takes 9.6 microsecs. - this seems a bit high, as create is just a Java "new" - and drop isn't any code at all (presumably, when the IP is no longer referenced, GC takes over...?).
Parenthetically, my JavaFBP VolumeTest executes 100,000,000 sends and 100,000,000 receives in 4 mins. on my 4-processor desktop, and keeps all processors 99% busy!
That seems quite poor for performance, even in Java. I.e. you're breaking it down to 420k IPs per second, even after buffering. Granted, I don't know the quality of your processors, the nature of the benchmark, or the size of your bounded buffers. But Erlang, Akka, AsyncFP, etc. tend to benchmark in millions of messages per second.
Dan: Yes, it was. It was fun, it created compact and efficient code. It could be dangerous? Yes, it could be. But again,
Arrogance doesn't have a strict definition either, but we sure know it when it happens.
That makes perfect sense! I'll give that idea a try when I get home tonight. By "token ring" I assume you mean a loop-type topology - and I will pay attention to the CPU utilization!
Paul
Sent from Samsung Galaxy Tab (tm) on Rogers
In my view, the point of a diagram is to communicate design intention to other humans.
The problem with self-modifying ASCII code was that maintainers found it hard to follow what was going on. A diagram that modifies itself during runtime, likewise, is useless from the perspective of maintenance.
Why would the rules be different when using a different syntax, say instead of ASCII, a syntax made up of lines and boxes?
Also, is a handoff the same as a context switch?
TIA
Paul
David Barbour <dmba...@gmail.com> wrote:
That's confusing! How is a one-process loop different from a regular Java program? Unless you are saying this is test for the minimal send/receive pair, with no possibility of suspension?
Also, is a handoff the same as a context switch?
I agree that your idea is the most reasonable text representation I've
seen. I may try it out on my next iteration (even if I continue to like
diagrams better, I will need an intermediate representation).