
Even the
best performing component can be hindered by incorrect use. Below we provide
practical recommendations on what should be used or avoided in application programming.
Following the tips below you will be able to create applications with the same
efficiency as this demo application. We also provide source codes for this
example to show how easy it is.
It is supposed
that programmers already know general principles of application design.
Nevertheless, we shall provide some useful links for better understanding of
.Net environment and tools for writing managed code: Writing Faster Managed
Code: Know What Things Cost
It is necessary
to pay attention to grid characteristics in different working modes, to
evaluate data volume to be displayed and to find a relevant chart for better
understanding of grid use.
Have only one
message loop per application. Don't create grids in different threads.
Let us assume
that the computer resources are not limitless. Theoretically the maximum
performance can be obtained if the number of threads equals to the number of
processor cores. While a lot of threads are creating, they aren't working in
parallel. In this case cores allocate time slices to threads based on their
priority and consistently perform context switches (context switch is
relatively expansive operation). Note, maximum time slice is about 10-15 msec.
We have also
take into account that each control paints its content in the GDI/GDI+ device
(via the Graphics object). While painting from one thread all others wait for
GDI device to perform painting in its turn. Therefore if we start many message
loops - it doesn't mean that we accelerate the application. In other words the
application losses time on context switches and on drawing in GDI device.
From our point
of view the application should have only one message pump. Windows has
additional mechanisms to optimize content drawing and we are not sure that they
work in case of multithreaded environment. Of course, business logic can work
in any thread, but the graphical thread should be only one in the application.
Use
MethodInvoker to synchronize threads.
In
multi-threaded applications every call should be synchronized with the main
thread containing windows message loop. Both Control.Invoke and
Control.BeginInvoke methods may accept different delegate types and their
parameters. However, this causes a serious performance issue as they call
Delegate.DynamicInvoke(params object[] args), which in turn uses
low-performance reflection. At the same time, for some delegates such as
EventHandler, MethodInvoker and WaitCallback the code is called directly. In
the time of code execution the delegate is checked for belonging to one of the
above types with specified number of parameters, and if it doesn't -
DynamicInvoke() is called.
Use objects of
arbitrary classes instead of collections of values of string[] type, etc. It is
more convenient and objects of arbitrary classes consume less memory than
string collections.
Don't format
values directly in data objects, i.e. if an object property is to return date,
this field should return DateTime object type instead of string type. Use data
formatting if needed. If properties return strings, they can be compared
incorrectly during data sorting. Besides, comparing two strings requires more
CPU resources than comparing two DateTime objects.
This working
principle is the same for all grids of all vendors. The main issue is that
PropertyDescriptor.GetValue() method uses reflection. NetGrid has an
optimization that enables it to receive notifications from
INotifyPropertyChanged/IBindingList without calling data object getters. Values
are required only at the time of painting and only for visible cells. If the
grid has a lot of rows, most of them are invisible and this approach
significantly saves CPU resources. It is worth considering in application
development. As an example, let's review subscription to Grid.RowUpdated event:
When updating
data in real time in applications, the grid stores highlighting information for
each updated cell. This default behavior causes serious consumption of memory
resources in addition to CPU resource consumption due to processing large
volume of information. As most updates can occur outside the visible area, the
programmer can save CPU resources by using the new property.
When this
optimization is used, vertical scrolling may bring rows without cell
highlighting information to the visible area and the user will not see cell
highlights that were made before rows get to visible area of the grid. This
concerns only highlighting information, while text and other cell content will
display correctly. The programmer should decide whether to use such
optimization or not.
Be very careful
about creating temporary objects as it may result in memory pressure and make
garbage collector collect unused objects more frequently. Please note that when
garbage is collected, all application threads are temporarily stopped.
Don't use
finalizers in objects unless necessary.
We hope that
these simple recommendations will help you create efficient and high-performing
applications.

0 Response to "Performance. Practical Recommendations"
Post a Comment