A few days ago I posted an article about the new .NET Expression features in .NET 4.0 (Fun with .NET 4 expressions). A few people commented and wrote the this was a pretty expensive way to synchronize data. Of course it was – performance wasn’t a design consideration. I merely followed the two rules of optimization:
- Don’t do it.
- (For experts only!) Don’t do it now.
And since the synchronization process was fast enough, I didn’t care.
However, just for the fun of it, I did some performance optimization and it is pretty amazing. The thing which made the original code rather slow was the fact that the same expressions were compiled over and over again. So an obvious improvement was to cache the compiled expressions and reuse them. So I introduced two dictionaries to hold the compiled expressions:
private static readonly Dictionary<Type, object> _SetterCache = new Dictionary<Type, object>();
private static readonly Dictionary<Type, object> _GetterCache = new Dictionary<Type, object>();
You may wonder why the type of the dictionary is Dictionary<Type, object>. The reason for this is that there is no other common base class for the type Func<TSource, TProperty>. The following this method checks the cache and compiles the expression if required:
private static Func<TTarget, TProperty> GetGetterMethod<TTarget, TProperty>(Expression<Func<TTarget, TProperty>> targetSelector)
{
object getterObject;
Func<TTarget, TProperty> getterMethod;
var selectorType = targetSelector.Type;
if (!_GetterCache.TryGetValue(selectorType, out getterObject))
{
getterMethod = targetSelector.Compile();
_GetterCache[selectorType] = getterMethod;
}
else
{
getterMethod = (Func<TTarget, TProperty>) getterObject;
}
return getterMethod;
}
I added a similar method to handle the update expression accordingly.
Finally, I hacked together a small test program which used the Stopwatch class to measure the synchronization speed. The result is quite impressing. Synchronizing an object with two properties 10,000 times yielded these results:
Elapsed for 10000 rounds (Slow): 00:00:08.0471936
Elapsed for 10000 rounds (Fast): 00:00:00.2009293
That is quite an improvement.
I’ve attached the source code to this post, so you can measure yourself.
Downloads
18846f28-3912-4484-ac13-11c99ae182b8|0|.0
Symptoms
After you view an ASP.NET webpage which
displays performance counter data via the PerformanceCounter class, scripts no
longer function. This includes scripts launched from a command line as well as
client-side scripts in any browser window that is opened after you viewed the
original page. Scripts are working again after you have stopped the Word Wide
Publishing service.
Cause
A deadlock occurs because of a bug in one of the WMI providers. An event tracing is done which calls the RegisterTraceGuids API which in turn calls into one of the WMI Service hosted within the Services.exe.
Resolution
A hotfix is available from Microsoft, at least in english and german.
To resolve this problem, contact Microsoft Product Support Services to obtain the hotfix for KB834010. For a complete list of Microsoft Product Support Services phone numbers and information about support costs, visit the following Microsoft Web site: http://support.microsoft.com/default.aspx?scid=fh;[LN];CNTACTMS
Status
This problem was first corrected in Microsoft Windows XP Service Pack 2
Steps to reproduce the problem
- Create a new ASP.NET web application
- Add a label control to the page
- Add this code to the Page_Load event:
1 using (PerformanceCounter counter = new PerformanceCounter())
2 {
3 counter.CategoryName = "Memory";
4 counter.CounterName = "Available MBytes";
5 Label1.Text = counter.NextValue().ToString();
6 }
- Compile the application
Open the webform with Internet Explorer
Now, open any website which has client-side scripting
References
abf5dc5c-d95d-468f-87a1-d5267e006e4d|0|.0
Tags:
performance, counter, asp.net, windows, internet, explorer
Technorati:
performance, counter, asp.net, windows, internet, explorer
Symptoms
After you view an ASP.NET webpage which
displays performance counter data via the PerformanceCounter class, scripts no
longer function. This includes scripts launched from a command line as well as
client-side scripts in any browser window that is opened after you viewed the
original page. Scripts are working again after you have stopped the Word Wide
Publishing service.
Cause
A deadlock occurs because of a bug in one
of the WMI providers. An event tracing is done which calls the
RegisterTraceGuids API which in turn calls into one of the WMI Service hosted
within the Services.exe.
<xsl:template match="xhtml:img" mode="xhtmlimage">
<xsl:param name="caption" select="@title" />
<
xsl:copy
>
<xsl:apply-templates select="@*" mode="xhtmlattributes" />
</
xsl:copy
>
<xsl:element name="span">
<xsl:attribute name="class">clsCaption</xsl:attribute>
<xsl:value-of select="$caption" />
</
xsl:element
>
</
xsl:template
>
Resolution
A hotfix is available from Microsoft, at
least in english and german.
To resolve this problem, contact
Microsoft Product Support Services to obtain the hotfix. For a complete list of
Microsoft Product Support Services phone numbers and information about support
costs, visit the following Microsoft Web site:
http://support.microsoft.com/default.aspx?scid=fh;[LN];CNTACTMS
Status
This problem was first corrected in Microsoft Windows XP Service Pack 2
Steps to reproduce the problem
-
Create a new ASP.NET web application
-
Add a label control to the page
-
Add this code to the Page_Load event:
using (PerformanceCounter counter = new PerformanceCounter())
{
counter.CategoryName = "Memory";
counter.CounterName = "Available MBytes";
Label1.Text = counter.NextValue().ToString();
}
Compile the application
-
Open the webform with Internet Explorer
-
Now, open any website which has client-side scripting
References
fee6ae42-6e28-46d1-b914-b1606a1788a8|0|.0
Tags:
performance, counter, asp.net, windows, internet, explorer
Technorati:
performance, counter, asp.net, windows, internet, explorer
Affected Products
- .NET Framework 1.0
- .NET Framework 1.1
Summary
The HttpWebRequest class performs poorly when sending requests to a server which contain a body.
Symptoms
The HttpWebRequest class performs poorly when sending requests which contain body data to a server. When monitoring the network traffic the following behaviour is seen:
- The client sends the header of the request to the server.
- After 350ms the rest of the request is send to the server.
Cause
The HttpWebRequest class waits for a HTTP1.1/100-Continue message before sending the body of the request. Additionally, the class supports the Nagle algorithm, which prevents the sending of many small packets to the same target. Instead, the server waits approximately 200 milliseconds, if there are other packets to be send to the same target. It then combines these requests in one packet.
Status
Microsoft has confirmed that this is a problem in the Microsoft products that are listed at the beginning of this article.
A hotfix exists (QFE810814) for version 1.0 of the Framework in the languages english and german. The patch is localized for other languages on request. Since it is a quick fix engineering (QFE), it can only be obtained directly from Microsft Support (PSS).
For the .NET Framework 1.1, no patch is necessary, since the behaviour can be controlled programmatically:
HttpWebrequest webRequest = (HttpWebRequest) Webrequest.Create("http://myserver/myfile");
webRequest.ServicePoint.Expect100Continue = false;
webRequest.ServicePoint.UseNagleAlgorithm = false;
Other Information
Note that you must have installed service pack 2 for the .NET Framework 1.0 before applying the patch.
Additionally, some configuration entries must be made in the machine.config file:
-
Create a new <settings> section within the <system.net> section with the following content:
<settings>
<servicePointManager useNagleAlgorithm="false" />
<servicePointManager expect100Continue="false" />
</settings>
-
In order for the .NET Framework to recognize this new section a settings sectionGroup handler needs to be added to the <configSections> portion of machine.config file:
<sectionGroup name="system.net" >
<section name="settings" type="System.Net.Configuration.NetConfigurationHandler, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</sectionGroup>
fd3424e6-4256-4613-b2fa-8488f8081103|2|5.0
Tags:
dotnet, httpwebrequest, performance, qfe810814, nagle, kbbug, kbQFE, kbdotnet
Technorati:
dotnet, httpwebrequest, performance, qfe810814, nagle, kbbug, kbQFE, kbdotnet