[NOTE: This post includes source code to a Winforms project with assorted examples that simply issues a PIPoint.FindPIPoints and the loads the results to a data grid view. For the purpose of the demonstrated code, I intentionally do not call AFOperations.FindPIPoints.]
I frequently write PI + WinForm applications. A common feature of my UI is to search for PIPoints and to load them into a data grid view. At its earliest root of inception, the PI Server was the Plant Historian, and anyone at a plant site generally got results extremely fast. I call this working on the Plant LAN, even though that Plant LAN may be composed of many LANs but the main point is that the Plant controls all the wiring at interconnections within the plant site.
Performance over a Plant LAN was generally very fast. For me to access over 70,000 PIPoints on a server on my Plant LAN takes less than 1.5 seconds. That’s not just to search for and retrieve those 70K PIPoints but to load them into a data grid view as well. This makes the user experience very rewarding!
The code to do this is quite short and straightforward. Consider this simplified example:
grid.DataSource = PIPoint.FindPIPoints(parameters);
Again the example is simplified. The FindPIPoints has multiple overloads taking an assorted of arguments, and I would assign them to a binding source's DataSource where I've already mapped that binding source to my data grid view. Despite the over-simplification, I trust the reader still grasps the overall intent. You fetch some PIPoints from a PI Server and assign them to a data source. It's that easy.
Fast Network on Plant LAN:
When it performs lightning fast, there is absolutely no need to tweak the code. The user experience is quite nice ... when you are on the same Plant LAN as the PI Server.
As PI evolved to be an enterprise solution, communication now took place over the Enterprise WAN. This involved going across a communications cloud. Perhaps it used leased lines from a telco. Or the Internet. There was some major portion of the journey where your company did not have full control of the wiring or the connections.
If you must remotely access a PI Server across the country or globe, it can take 10, 30, 60 seconds or more to fetch many thousands of PIPoints. This is not the fault of the AFSDK nor the PI Server, which is blazing fast on a Plant LAN. The performance is at mercy of your Enterprise WAN. On a bad one, it leads to a horrible user experience.
If you do not have a horribly laggy network, then I hate you salute you. You have no need to run this application or to read further. You should stick to the simplest, most straightforward coding method available.
However, if you have a horribly laggy network, this application can demonstrate different techniques to improve upon the user experience. No one experience is inherently faster than the other. But one experience may completely lock the UI making the form appear unresponsive, whereas another may still take 30 seconds to load the tags but at least the UI responds to form move requests, etc.
Same Code on Same PI Server but across Enterprise WAN:
Yikes! The same task that took 1.4 seconds on the Plant LAN takes 23 seconds on the Enterprise WAN.
Obviously to have a responsive UI means work is performed on thread different than the UI thread. There are 2 ways I show to do this. One is with the legacy Backgroundworker component, and the other is with the newer Task. One key reason why I wrote this application was because I use the Backgroundworker component a lot but have held off on working with Task. I wanted to create a simple example of some Backgroundworker code that would be translated to the newer Task.
For Backgroundworker and Task, each has 2 different techniques to find PIPoints and load them to a grid: a "Full" method and a "Partial" method.
The "Full" method will not attempt to load the grid until the PIPoints have been fully fetched first (warning: alliteration overload). During the fetch time you will see the elapsed timer is running smoothly and you may move the form around to your liking. While the fetch is pending, the grid and its row count is unchanged. During the very brief load phase, there will be a slight drag on the UI.
The "Partial" method attempts to load the grid in partial groups of 1000 PIPoints. The grid will eventually be fully loaded despite my use of "Partial". The user experience is mixed. Depending upon your network, the grid loading of the first 1000 PIPoints will freeze the UI for many seconds. After he initial grid load, the UI is once again quite responsive. The elapsed timer is once again running smoothly and you may move the form around to your liking. And the row count should appear to be increasing until full completion.
In a nutshell, the straightforward method completely locks the UI, the "Full" background threads have a responsive UI but an empty grid until the very end, and the "Partial" threads start off sluggish but later becomes quite responsive with a populated grid.
You are encouraged to examine and experiment with attached project source code. Observe the behavior and user-experience provided by the assorted buttons.
Before ending, there is one last bit of business to address:
THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
With that said, I welcome any feedback, comments, or otherwise constructive criticisms.
DOWNLOAD VISUAL STUDIO PROJECT FILE HERE: