Posted by: Dennis | May 18, 2009

How to do parallel work with PageMethods

Let take an trivial example. Here we make 4 asynchronous calls to the server to some function call DoWork.

function pageLoad() {

   PageMethods.DoWork(OnSucceeded, OnFailed);

   PageMethods.DoWork(OnSucceeded, OnFailed);

   PageMethods.DoWork(OnSucceeded, OnFailed);

   PageMethods.DoWork(OnSucceeded, OnFailed);

}

The DoWork method returns the time it started and the time it finished:

[WebMethod]

public static string DoWork()

{

  DateTime dt = DateTime.Now;

  Thread.Sleep(2000);

  return "Success @ " + dt.ToString(DateTimeFormatInfo.InvariantInfo) + " - " +

    DateTime.Now.ToString(DateTimeFormatInfo.InvariantInfo);

}

If you create a brand new project in Visual Studio and run the above, you will get something similar to:

Success @ 05/18/2009 20:04:52 – 05/18/2009 20:04:54
Success @ 05/18/2009 20:04:52 – 05/18/2009 20:04:54
Success @ 05/18/2009 20:04:52 – 05/18/2009 20:04:54
Success @ 05/18/2009 20:04:52 – 05/18/2009 20:04:54

And then 10 minutes later when you try to do the exact same thing on your production environment and test it you get:

Success @ 05/18/2009 20:18:09 – 05/18/2009 20:18:11
Success @ 05/18/2009 20:18:11 – 05/18/2009 20:18:13
Success @ 05/18/2009 20:18:13 – 05/18/2009 20:18:15
Success @ 05/18/2009 20:18:15 – 05/18/2009 20:18:17

This was probably not what you were expecting. The reason is rather obscure. If you simply have a Global.asax then ASP.NET will take an exclusive lock on your session object on every call to the server for a given Session.

This mean that in practice, your users can only make one call to the server at a time.

So how to fix?

On might think that disabling the session access to the WebMethod is enough, like this:

[WebMethod(false)] <------- HERE

public static string DoWork()

But that would be incorrect. In fact that does absolutely nothing.

Instead you have to mark your whole PAGE with no session, using the setting in the aspx page:

EnableSessionState=”False”

That will again return dates that are the same for each call. Well almost at least. If we increase the number of calls to the server to e.g. 8, what we get back is:

Success @ 05/18/2009 20:24:47 – 05/18/2009 20:24:49
Success @ 05/18/2009 20:24:47 – 05/18/2009 20:24:49
Success @ 05/18/2009 20:24:47 – 05/18/2009 20:24:49
Success @ 05/18/2009 20:24:47 – 05/18/2009 20:24:49
Success @ 05/18/2009 20:24:48 – 05/18/2009 20:24:50
Success @ 05/18/2009 20:24:48 – 05/18/2009 20:24:50
Success @ 05/18/2009 20:24:49 – 05/18/2009 20:24:51
Success @ 05/18/2009 20:24:49 – 05/18/2009 20:24:51

The reason is that now the browser is restricted by opening too many connections at the same time. So even though it will look like it is calling all 8 methods on the client side (the javascript call returns, FireBug will show nice graphs saying they are all called at the same time, etc.) then in reality it waits until a connection is available.

But what do you do when you actually need to use Session somewhere in your page or you have a nice 4+ CPU machine you actually want to utilize? Well, that gets a little tricky.

First we have to change the client side. Instead of making a single webmethod call, we need to first make a call to a “Begin” method and then a call to an “End” method to get the result.

function DoSomeWork() {

   PageMethods.BeginDoWork(OnSucceededBegin, OnFailed);

}

function OnSucceededBegin(result) {

   PageMethods.EndDoWork(result, OnSucceeded, OnFailed);

}

On the server side it gets even more tricky.

   1: [WebMethod]

   2: public static string BeginDoWork()

   3: {

   4:    string g = Guid.NewGuid().ToString();

   5:    Func<string> f = () => DoWork();

   6:    IAsyncResult call = f.BeginInvoke(null, f);

   7:    lock (OnGoingWork)

   8:       OnGoingWork[g] = call;

   9:    return g;

  10: }

  11: private static readonly Dictionary<string, IAsyncResult> OnGoingWork = new Dictionary<string, IAsyncResult>();

In line 4 we create a token. In line 5 we make a lambda function which calls our original method. In line 6 we start the execution of it on another thread, notice the 2nd parameter is the lambda function. Line 7 to 9 stores the IAsyncResult in a static variable using the token as identifier.

   1: [WebMethod]

   2: public static string EndDoWork(string guid)

   3: {

   4:    IAsyncResult call;

   5:    lock (OnGoingWork)

   6:    {

   7:       call = OnGoingWork[guid];

   8:       OnGoingWork.Remove(guid);

   9:    }

  10:    Func<string> f = (Func<string>) call.AsyncState;

  11:    call.AsyncWaitHandle.WaitOne();

  12:    return f.EndInvoke(call);

  13: }

In the “End” function we then need to get the result of the asynchronous call. Line 5 to 9 fetches the IAsyncResult out of the static variable and cleans up the. Line  10 gets the lambda function out of the IAsyncResult with the small hack from line 6 in the “Begin” function. Line 11 waits for the call to actually finish, and then in line 12 we get the result.

And voila:

Success @ 05/18/2009 20:28:48 – 05/18/2009 20:28:50
Success @ 05/18/2009 20:28:48 – 05/18/2009 20:28:50
Success @ 05/18/2009 20:28:48 – 05/18/2009 20:28:50
Success @ 05/18/2009 20:28:48 – 05/18/2009 20:28:50
Success @ 05/18/2009 20:28:48 – 05/18/2009 20:28:50
Success @ 05/18/2009 20:28:48 – 05/18/2009 20:28:50
Success @ 05/18/2009 20:28:48 – 05/18/2009 20:28:50
Success @ 05/18/2009 20:28:49 – 05/18/2009 20:28:51

Posted by: Dennis | April 22, 2009

Aspnet_Compiler compilation speed (Part 2)

In a previous post I discussed some of the things we could do to speed up the aspnet_compiler. Today I shall talk about some of the more exotic things to mess up.

Fixed Names

FixedNames is the setting in the gui called “Create a separate assembly for each page and control output”. When you do this, then each individual file is compiled on its own, and ASP.NET is super slow at doing this.

Unfortunately it is sometimes necessary. In some source you may get errors at runtime that a certain dll could not be found. I haven’t discovered the exact circumstances that causes it, but I suspect it has something to do with circular references between pages and controls.

You can check if you will run into this if you compile in the default merge too 1 assembly and in the fixed name mode with merge enabled anyway (You can only do this in the wdproj file directly) and the result are identical.

Avoid Copy

Based on feedback from multiple users we have enhanced WDP so that it does not wipe out the precompiled web from previous WDP run until the current WDP does not build successfully… This is specifically useful if you have created IIS Virtual directory pointing to the output location…  Now even if your current WDP build does not succeed your web site in IIS will still continue to function… At the same time this also implies that it will be important to take a note of the WDP output in the VS output window before grabbing the deployed output for any further processing as your output folder might have the output from the previous build…

This is from the VS 2008 version of Web Deployment Project (WDP). If you noticed a severe drop in performance between 2005 and 2008, this is probably the reason.

What it actually does is make a temporary directory, where it copies all of the files to, then completes the compile as normal, deletes the old deployment dir and then copies the tempdir over to the deployment dir and then deletes the tempdir… Now, why don’t they actually just MOVE the tempdir to the deployment dir and save the double copy? Perhaps something to do with permissions on the deployment folder.

No matter the reason, it seems like a good idea to fix it. The easiest is obviously to disable the temporary copy, but if you actually need the original to be usable even if the build fails, then obviously you cannot do that.

The other thing you can do is use that ramdrive you already set up for the tempdir. In order to do this, you need to edit the msbuild source of WDP. Specifically lines 89-91:

<CreateProperty Value=".\TempBuildDir\">

  <Output TaskParameter="Value" PropertyName="TempBuildDir" />      

</CreateProperty>

Just change the value to point to somewhere on your ramdrive.

Posted by: Dennis | April 16, 2009

Aspnet_Compiler compilation speed (part 1)

The Aspnet_compiler is a really useful util to precompile websites, so that the startup time in production environments are minimized and that none of the actual aspx pages needs to be part of the deployment.

However, it is also a real piece of crap from a performance perspective, reflecting the truely horrible performance that Asp.Net also has upon start-up. Which is no surprise since they use the exact same way of compiling sites.

Therefore we can also use various techniques for speeding up asp.net to speed up the aspnet_compiler.

First of all, you should not be running the aspnet_compiler as part of your normal build. That is just a waste of time. Instead let your auto builder do it after you commit your code (Because you are running a source repository and you do have a build server, right? Otherwise, implement that as the very first thing).

Second thing is to setup defrag on your drives on your build server. They become extremely fragmented if you have lots of people committing code. Obviously. if you have a SSD you don’t need to do this part (at least until there is a SSD compatible defragger).

Next depends on how much memory you have in your build server. If you have “enough", then make a ram drive for the following, otherwise simply just use a different drive from where your source code is located.

Third is to move the temporary location that asp.net uses to a faster location. You do this by editing either the web.config in %systemroot%\Microsoft.NET\Framework\v2.0.50727\CONFIG if your build server is dedicated to building, or in the individual web.config files (just remember not to commit them). The former is highly recommended.

What you want to edit is the tempDirectory of the compilation tag. Point it to a folder on the drive you selected above. Remember that this folder must have similar permissions as the %systemroot%\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files folder, which is the default.

I have a few more up my sleeves, until next time.

Posted by: Dennis | April 2, 2009

What to do when the known world goes broke?

USA is on the brink of bankruptcy, and it seems most European banks have also been lying about their books using AIG.

The result is the outlook to a greater depression than the one that was seen in the 1930s. The question is then… What will the world look like when the true depression hits? And how will it look like afterwards?

Posted by: Dennis | March 31, 2009

A web shop (Part 1)

image I really tried. I did. I started up the Entity framework and wasted hours upon hours on trying to make it do even the simplest little thing.

The thing I was trying to do was create 3 super simple tables: A product, a Product_Language containing translations of any text associated with the product and finally a language table to hold stuff like the ISO code and stuff.

Problem 1: The brain dead ESMX editor does not actually allow you to create tables. Uh no, that has to happen somewhere else.

Problem 2: That somewhere else inside of Visual Studio is the Data Connections Manager. I am not sure I would recommend this to even my worst enemy. In order to make a product table with 1 (yes 1) column, you have to click on the following:

  • Menu bar –> View –> Server Explorer
  • Navigate your way into Data Connections –> <your connection> –> Tables
  • Right click Tables and click “New table”
  • Write Id <tab>
  • Now I don’t know exactly how many firing neurons the guy who made the default Datatype had. But I am sure a lot of people hate him for choosing “nchar(10)” as the default. Perhaps it was choosing, because noone in their right mind would ever choose this for any real columns, thus forcing the user to think. Hint Microsoft: When I name something “Id” at the end of the word, the datatype I want is probably int. Anyway, type “int” <tab>
  • Press space to deselect “allow nulls”. Again we have the guy with lack of firing neurons choose the default. Joel has a thing about people not figuring out how recursion and pointers work (he is right btw.), I on the other hand have noticed that peoples eyes go similarly blank when you begin to talk about nullability. People just don’t understand nullability. If you don’t know what it is, don’t use it. About the only place where you really NEED it, is when you have foreign keys you want to have optional. Otherwise, leave it to people that understand nullability.
  • Now use your mouse to expand the “Column properties”, so that you can actually find the thing you are looking for. Assuming of course you are reading this, so that you know you are looking for something down here.
  • Expand the little plus next to the “Identity Specification”, then double click the “No” in the “(Is Identity)” to change it into a “Yes” (because double clicking the exact same “No” it in the “Identity Specification” will do exactly nothing)

Congratulations, you have now spent 10 minutes on something that could be written in 10 seconds: “Create table product (id int primary key not null identity)”

Problem 3: Every time I closed the ESMX editor to see if the weird errors it would spew, then it could not be reopened again. Restarting VS was the only option.

Problem 4: For some weird reason it would not accept my multi column key on the product language table. This was solved by simply deleting the ESMX and starting over again…

Problem 5: I do not know how many hundreds of mouse clicks I needed to go through that editor to figure out just the tiniest things.

It actually works now:

image

But I will not try the ESMX editor again, for a very very long time. So next time… Creating the same thing with NHibernate.

Posted by: Dennis | March 31, 2009

Pixel Qi screens coming to an eBook reader near you

It seems that Pixel Qi has finally put their screens into production and someone has put them in an eBook reader.

Pixel Qi are those people that made the screen for the OLPC, the super cute little green laptop for children in developing countries (oddly enough USA is not registered as a developing country)

Looking forward to being able to put my reading on an eBook, instead of wasting paper and money printing it.

Posted by: Dennis | March 29, 2009

Forgive me, for I have sinned

I forgot Earth hour. There I admitted it… Was installing VS and forgot all about it.

That reminded me of a cafe on the way to work which was advertizing with “We will turn off the lights for one hour, and instead burn candles”. This illustrates just why humans are unfit for inhabiting earth. Except me, my friends, my family, everyone involved in products I use and produce, and of course their family and friends and everyone involved in products they use and produce etc.

Let us just examine exactly what it means to replace 1 hour of electrical lights with 1 candle. 1 hour of light with an old energy hungry 60W light bulb would use a massive 0.06KWh. This site rates that we pollute appx. 0.37kg CO2 per KWh. So we would have polluted 18.5 grams of CO2. Moneywise, it probably cost around 0.5 cents with current VN prices.

A candle however is harder to estimate. Let us consider just what it takes to even be allowed to burn it in the first place. First we need to bring it to the cafe from where ever it was bought. Someone had put it on shelfs there, presumably using some machinery and some resources to actually process the sale of the item. To even get it to supermarket, someone else had to drive it there from the packaging central, which again had it transported from somewhere. At some point at the end of all this transportation, we will find a factory.

At this factory, they used resources to package the candles, they used resources to form the wax that was just melted in a big melting pot. And I don’t even know where the wax or packaging materials came from. We do know that moneywise the candle is about 1 USD.

So this cafe replaced a highly optimized delivery system of electricity to an electrical light, with an item that requires hundreds of people and thousands of kilometers of physical transportation. Not to mention it cost the cafe 200 times more.

I do like candles, but they should definitely not be used as a REPLACEMENT of electrical light for the purpose of saving the environment.

Posted by: Dennis | March 28, 2009

Silverlight RIA

I’ve taken a look at the new Microsoft RIA Service.

At first glanze it seems really cool. You simply mark some classes in your service side code with “[EnableClientAccess()]” and it will then automatically generate proxy classes for you to use it on the Silverlight client side, and not just silly copies either. No, they glaze them with sugar and add nice code to make them play nice with data binding. Beautiful!

3.12 The shared file copy algorithms
During the code-generation phase, all files named according to the pattern *.shared.cs or *.shared.vb will be copied verbatim into the client project. Any folder structure in the server project will be replicated in the client. The code generation process does not interpret these files; they are simply copied.

This is fine… Except for one small detail. Why do these files need to be COPIED? Visual Studio already allows you to link to an existing file somewhere outside of your project.

3.9 The code-generation algorithms

- All assemblies referenced or built by the server project are analyzed.

Beautiful. That allows us to put all of this into a separate project.

4.9.2 Complex Supported Types
The following complex types are supported:

Where is my IDictionary?!? Where is IXmlSerializable?!?

It is important to note that all domain operations do not support method overloads. More concretely, if you want to have multiple query methods in the same domain service with different number of input parameters (e.g. GetEmployees() and GetEmployees(string)), you’ll need to name them differently.

Please support this. There doesn’t seem to be a technical reason for it. Except that each of them is blown up to 3 functions on the client side, but that should still allow for the original overload, will just have 6 functions.

Overall though, it looks great!

Posted by: Dennis | March 28, 2009

Snailmail

A package with a Click-N-Ship label created on usps.com containing the following information is scheduled to be shipped on 03/20/2009.

Type of Service: Priority Mail International Large Flat Rate Box

Today is the 28th… I don’t know about you, but I usually associate paying 63$ for a PRIORITY mail as arriving in days.

Instead this is what you get:

image

As in WOW, they didn’t even get it out of the original package center yet.

Posted by: Dennis | March 28, 2009

First glanze @ windows 7

It feels like Windows. This is actually saying a lot.

I like it too. Nothing annoying has come up in the last 4 hours, except for the turtle speed internet, but somehow I don’t think Microsoft will fix that for me. Joel says it so much better than me why this is important.

That being said, there are some weird things.

I don’t get the design they made for the things in the lower right corner. Why does it have to be so WHITE? Perhaps they thought that no-one cares about these icons, so we better make them as invisible as possible. I have an idea, why not just remove them totally if they are not supposed to be seen?

image

Something else that I just noticed. Why is there a keyboard symbol here? Does everyone in this world have 2 keyboards attached to their computer, one for the right hand and one for the left? Why is the one that I choose at install time not good enough? Not everyone owns a US keyboard you know.

Older Posts »

Categories