Search Search

#1 worldwide
FREE Coding Lessons

since 1996
   THE BEST WAY to learn ASP & Asp.net!
Advertise Here!
click for details
Credits Host:
DiscountASP.net
Server Admin:
The "Team"
Contact Info.
Charles M. Carroll

my Blog
[prev. Lesson]  VB: General Building Guidelines
     [next Lesson]  MTS - Microsoft Transaction Server

VB Component Threading Details
by Charles Carroll
special thanks to Jon Flanders, Stephen Martin and Juan Llibre

Component written in Visual Basic are affected by some complex threading isses we will discuss here. The "bible" for all this is:
Programming Distributed Applications with COM and Microsoft Visual Basic 6.0
by Ted Pattison, Published by Microsoft Press.

Objects created and destroyed at the page level scale very well. Once a session level object is created it is attached to a specific, discrete thread. That thread can never be destroyed until all users assigned to that thread either <%session.abandon%> or their session times out. This is the internal workings of the ASP execution environment. Don Box wrote this fascinating detail up a couple of MSJs ago.   Objects created with a session scope, i.e.

set session("whatever")=server.creatobject("whatever.id")

do not scale well and are affected by the threading issues in the following way:

  • You tie the Session down to a particular thread ( instead of ASP being able to use any thread from the thread pool).
  • If you place a object marked apartment into the SessionObject you have an object  which can only live and be called from the Single-Threaded Apartment it was created in, ASP must run ALL request for that Session in that STA.
  • If you don't do this (or only place Apartment Neutral Objects in the SessionObject ) ASP will run requests for that session on the first available thread.

So imagine - you have a four processor machine running IIS/ASP - forty people come into your site, now each of those requests is now tied to a specific thread, now two requests stop (are not currently making requests) - one more comes in and gets dispatched to one of these two threads that are free, and one of the two that stopped comes back - but another Session is using that thread - there are now free threads that cannot be used - they are just sitting there doing nothing - while a user is waiting for its thread to be freed. This is just one example of what can go wrong (not to mention the additional work ASP must do to make sure this all works correctly). Overall placing object marked Apartment into the SessionObject is a very bad thing. You are way better off instantiating on every page.  You are correct - that you cannot place an Apartment threaded object into the ApplicationObject - which is probably what they should have done with the SessionObject as well.

All calls that involve objects conversing must be proxied. The proxy referring to is what the COM runtime creates in an Apartment when that Apartment receives an interface to a COM object which lives in another Apartment.

For example - if you use a COM object which is marked "Free" in the registry - ASP will create that object and it will live in the Multi-Threaded Apartment (MTA), the page which is executing in a Single-Threaded Apartment (STA) will not get direct access to the object - but will talk to the object through what is called a proxy. The proxy looks just like the interface to the Page (has the same methods etc), but when the page calls a method, the proxy forwards the method call (parameters, name etc) to a COM provided channel. This channel calls what is refered to as a stub - which again looks just like the object - but lives in the same Apartment as the Object (in this case the MTA). Then finally the object gets called and then returns throught the same method. This is 1000xs slower that if the object lived in the same Apartment as the page (because of a thread switch - so switching threads you can see is very expensive). This is just how COM works.

When a COM object is redesigned to be stateless and run under MTX, objects in the same package are not crossing process boundaries. Different packages are!

Run the scenarios:

Scenario 1: So if for example,
+ 100 people hit your site for a couple of pages and leave
+ 100 new people arrive in a couple of minutes
+ 200 people arrive after that and then
+ 50 people
=====
450 sessions/objects in memory with 50 !!! people on your site. And dozens or hundred of threads that can't be reclaimed for a while

Scenario 2:
+ 100 people hit your site for a couple of pages and leave
+ 100 new people arrive in a couple of minutes
+ 200 people arrive after that and then
+   50 people
=====
50 objects in memory because you destroyed all objects at the page level. No threads tied up.

If it isn't Apartment Neutral (i.e. aggregates the Free-Threaded Marshaller) - you will tie the session down to that thread - so you have to ask yourself - is tying my sessions down to a specific thread a major performance hit - and that really depends on how many users are hitting your site and how often. In general I think it is a bad thing and should be avoided - unless there is no other way to accomplish what you want - and there almost always is a way - that isn't too much work and doesn't have any negative side-effects

This is why I have <%@enablesessionstate=false%> and a blank global.asa. If I need an object, I create and destroy it at the page level. for almost every page on my site and with 10,000 sessions a day and 90,000 page views we still serve pages fast and don't get locked up very often.

There are many worthy charities!!. But perhaps help starving children in Africa or South America AND help Charles too. a $5 tip buys him lunch at McDonalds, a $20 tip buys his kid Hitoshi a new computer game, a $39 tip buys his daughter Michiko a few nice outfits. See our donor list.