08-07-2012 08:44 AM
Hi,
I have the following situation: I am serving data to clients and spawn a "handler" for each client that is connected. The clients will do "read" operations in 99.999% of the cases.
The data I'm serving is "created" in a processing machine which updates a functional global 2D array with new data. The 2D array size is fixed on boot-up based on configurations.
Currently, each data client handler will access elements or sub-elements (read one / read sequence) by calling the functional global which will return the data set requested. This action is blocking. The clients require timely responces. I can easily handle a handful of clients at a moderat rate, but I would like to decouple the client "Read-only" operations more from the central data storage.
Does anyone know if doing a "preview" on a notifier is a blocking action? If it is NOT, then I can simply have each client handler "preview" the notifier to get the latest data, and when the "producer" has updates, it will just put it on the notifier. This guarantees all clients always look at the most recent data available at the time of the request, and prevents them from blocking one another.
The other alternative is using a global variable.. I know for the most part this is considered "bad" but is this one of the cases where it may be acceptable? While I wouldn't be able to have a compiler guarantee that it will only be written to in one place, as the single developer of this application, I can.. As such, we essentially have a situation with one writer and multiple readers in which case a global might be considered the optimal solution from a performance point of view?
I would like some comments on this, in particular : Is Previewing a Notifier a Blocking Action? (what about previewing a Queue? Is that blocking?)
Thanks,
Q
08-07-2012 09:59 AM
1. With multiple readers, a Notifier is a more natural fit than a queue. However, you may still have some tradeoffs compared to a functional global. The functional global encapsulates the 2D array access and allows you to do more in-place operations. A Notifier will make a copy of its data for each reader. On the other hand, the signaling properties can be a big advantage over polling a functional global.
2. Getting Notifier Status is not a blocking function, but it reduces you to polling again. I typically use Wait On Notification, usually with Ignore Previous == False. Wait On Notification is not a blocking function in the same sense as a functional global in that multiple readers do not have to "get in line" for access to the data.
3. Have you looked into DVR's at all? They just might be another option to consider. I'm not very experienced with them though, so couldn't say for sure whether they suit your app.
-Kevin P
08-07-2012 10:07 AM
I'm not sure if previewing notifiers or queues is blocking but I did want to comment on the global variable. If you can guarantee that you will be writing to a global variable in one place, and if stale data is not a problem, then I see no issues with using them. They are extremely fast. I don't know if they are blocking.
08-07-2012 10:31 AM
Kevin,
I did consider DVR, but DVR's are by my understanding blocking.
I am actually not polling in my case since I would only "preview" when I need data (e.g. when a client makes a request) so I don't have any polling conerns. For that reason a "wait on notifier" is not what I want for my case since I want my client server loop to essentially sleep until a request is made. The "wait on notifier" would wake it up every time I update the master table which is not necessary.
I did some experiments with the real-time trace toolkit (I forgot to mention that this will be on a RT target), and I'm not quite sure, but from what I can tell, the notifier status is indeed not blocking.
08-07-2012 10:36 AM
Thanks, I'm leaning in the Global variable direction on this one.. I will do some more testing and report back.
08-07-2012 10:44 AM
When I made the comment about global variables I did not know you were using real time. I don't have any experience with real time so you might want to check if there are any issues using globals in that environment. I remember Ben swearing off globals because of something that had to do with timing but I don't know if he was using real time or not. I think it had to do with timed structures finishing late.
08-07-2012 11:56 AM
Yes, I remember reading that too, I think this is "different" though, but I should probably try and dig that post up again.
In the mean time I'm having a little bit of a hard time interpreting my trace files..
The test is setup with a top-level vi (normal priority, no debugging) that starts the trace logging, then runs a "high priority" write global.vi that updates the global
In parallel to the write global.vi there are 3 instances of a re-entrant "above normal" priority vi called read global.vi.
In the trace log, I see no activity at all on the "read global.vi"'s or on the "above normal" thread view, though the named entries are there. I know the 3 threads are running because of output to indicators at the end of the runs..
Its just confusing and ends up telling me less than I had expected.. Also, not sure why there are 3 standard high threads or which one would correspond to "my" high priority VI? and why are there 4 (0 through 3) "normal", "high" and "above normal" threads in the thread view and the VI view?
Guess I need a class in how to use the RT trace tool kit or something.
08-07-2012 12:14 PM - edited 08-07-2012 12:18 PM
Can't comment on standard globals in RT either, but if you maintain discipline to write to it in only one place, I'd agree that a regular global ought to work.
That said, I'd probably still try to use a functional global until I was forced away from it. Since your clients don't poll at a high rate but only need to read data on demand, it seems that both the likelihood and severity of "blocking" one attempted read while waiting for another to finish is probably rather small. Trade that off against the way a functional global gives you some nice capabilities for in-placeness, minimizing data copies, and providing a structure on which to hang useful debug code if/when the need arises.
-Kevin P
P.S. Just saw that you posted between the time I started and finished my msg. Looks to me like a functional global might already help you with debugging... (Can always revert back to standard global, if necessary, after working out the kinks).
08-07-2012 02:47 PM
Yes, its infrequent, but what I'm trying to reduce is the delay between RX'ing a request until the TX responce of that request is sent. The largest jitter source seems to be the access to the functional global I have currently. Keep in mind that each client can poll at "stupid" rates like once or twice every 100 ms, and I can have multiple (5+) different clients connected.. The infrequent remark is on the "writing" side of things. Clients will almost NEVER try to do a write (and if they do, it gets routed to the data processing loop anyway, even with the current functional global design, so the write in only one place is maintained), and the data processing loop is also infrequently updating the data table (maybe once per 30s in the "worst" case, and more likely once per 10-12 minutes (per instrument, of which I can also have multiple).
So, just a long winded way of saying that the blocking is an issue in heavy load cases, because the reading clients will block each other, and I think this would be less of an issue if they were reading a global or a notifier.
08-07-2012 03:18 PM
So reading in the long thread by Ben from 2006 which discuss gloals vs functional vs. occurence, vs queues vs notifiers is interesting.. however his problems seems to have been tied to UI interactions. On the RT there is no user interface per se, so globals should not have the issues that he saw... pressumably.
Due to the weirdness of the trace-log, I still can't tell if reading a global will block a) other read operations or b) writing to the global.