Clarity, Technology, and Solving Problems | PracticeThis.com
WP7 App with Key Windows Azure resources – Slides, Videos, How-To’s, and T-shooting – for quick consumption on the go.
Your ASP.NET application performs slower than expected? How many times do you access your database for each request? Did you use SQL Profiler to find out? Did you know that chatty database access is one of the most common performance sins (this is my own observation)?
Want to improve? - Reduce the number of database queries.
Not an option? - You may want using multithreading. Proceed with caution.
You need to run 3 independent heavy database queries – Q1, Q2, Q3. You need to use the result from the three – Result = Q1+Q2+Q3. You never know the order in which each query completes. It can be: Q1Q2Q3, Q1Q3Q2, Q2Q3Q1, Q2Q1Q3, Q3Q2Q1, Q3Q1Q2. Missed any combination? Run one after another would create significant latency. Running each on its own thread would create latency of Max(Q1,Q2,Q3) which is less that sum of the three.
How to run each query on its own thread and wait for the completion for each one?
The following code spawns three threads and waits for all to join, and then use the results from each.
1: Thread t1 = new Thread(DoWork1);
2: t1.Start();
3:
4: Thread t2 = new Thread(DoWork2);
5: t2.Start();
6:
7: Thread t3 = new Thread(DoWork3);
8: t3.Start();
9:
10: t1.Join(1000);
11: t2.Join(1000);
12: t3.Join(1000);
13:
14:
15: Label1.Text = (i1 + i2 + i3).ToString();
See any issues using it in ASP.NET? One caveat though, creating threads manually like this may cause performance hit as it involves context switching – CPU consuming operation. Consider using ThreadPool object.
ThreadPool is preferred as it already has live threads allocated for you. No need to ask for a favor from CPU in the moment of truth. Here is the code:
1: public partial class _Default : System.Web.UI.Page
2: {
3: int i1 = 0;
4: int i2 = 0;
5: int i3 = 0;
7: WaitHandle[] waitHandles = new WaitHandle[]
8: {
9: new ManualResetEvent(false),
10: new ManualResetEvent(false),
11: new ManualResetEvent(false)
12: };
15: protected void Page_Load(object sender, EventArgs e)
16: {
17:
18: }
19:
20: protected void Button1_Click(object sender, EventArgs e)
21: {
22: Stopwatch sw = new Stopwatch();
23:
24: sw.Start();
25:
26: WaitCallback method1 = new WaitCallback(DoWork1);
27: bool isQueued1 = ThreadPool.QueueUserWorkItem(method1, waitHandles[0]);
28:
29: WaitCallback method2 = new WaitCallback(DoWork2);
30: bool isQueued2 = ThreadPool.QueueUserWorkItem(method2, waitHandles[1]);
31:
32: WaitCallback method3 = new WaitCallback(DoWork3);
33: bool isQueued3 = ThreadPool.QueueUserWorkItem(method3, waitHandles[2]);
34:
35: if (WaitHandle.WaitAll(waitHandles, 5000, false))
36: Label1.Text = (i1 + i2 + i3).ToString();
37: else
38: Label1.Text = "Problem";
39:
40: }
41:
42: void DoWork1(object state)
43: {
44: int.TryParse(TextBox1.Text, out i1);
45:
46: //HEAVY QUERY GOES HERE. Sleep is for the demo only! Remove it!
47: Thread.Sleep(i1);
48: ManualResetEvent mre = (ManualResetEvent)state;
49: mre.Set();
50:
51: }
52:
53: void DoWork2(object state)
54: {
55: int.TryParse(TextBox2.Text, out i2);
56:
57: //HEAVY QUERY GOES HERE. Sleep is for the demo only! Remove it!
58: Thread.Sleep(i2);
59: ManualResetEvent mre = (ManualResetEvent)state;
60: mre.Set();
61: }
62:
63: void DoWork3(object state)
64: {
65: int.TryParse(TextBox3.Text, out i3);
66:
67: //HEAVY QUERY GOES HERE. Sleep is for the demo only! Remove it!
68: Thread.Sleep(i3);
69: ManualResetEvent mre = (ManualResetEvent)state;
70: mre.Set();
71: }
72:
73: }
If your function calls on COM object – avoid using ThreadPool, its Apartment model is not compatible with COM and it cannot be changed. More info - Pitfalls With .Net Multithreading And COM Objects – Threads Must Have Compatible Apartment Models (MTA vs. STA).
Another point to call out is that performance improvements based on multithreading is subject to amount of available CPU’s. Test your solution first!
This post was written with help from Lior, MCS Israel Architect.
Download sample project with the code from my SkyDrive:
Enjoy.
Be alert when implementing multithreading .Net in conjunction with COM objects. Thread apartment models matter.
.Net threads have Multi Threaded Apartment (MTA) model by default. COM objects have Single Thread Apartment (STA). Calling on COM objects on .Net threads that you spawn may cause unpredicted result.
Multithreading in .Net is easily implemented based on either Thread or ThreadPool objects. Thread.Start() method spawns new thread which has Multi Threaded Apartment (MTA) model . ThreadPool.QueueUserWorkItem(myMethod) queues myMethod to be executed on available thread managed by it.
When spawning your own threads with Thread.Start() set Thread’s apartment model to STA if you plan calling COM object on it:
1: Thread t = new Thread(DoWork);
2: t.SetApartmentState(ApartmentState.STA);
3: t.Start();
Note, spawning your own threads with Thread.Start() utilizes resources – mainly CPU, spawning too much threads may cause performance hit. Consider using ThreadPool object.
All threads managed by ThreadPool objects are MTA threads. Apartment model of ThreadPool’s threads cannot be changed. Do not call COM objects on ThreadPool’s threads.
“Most COM components will work with ASP.NET…” “…The AspCompat attribute forces the page to execute in STA mode. The runtime throws an exception if the compatibility tag is omitted and an STA component is referenced on the page.”
“Most COM components will work with ASP.NET…”
“…The AspCompat attribute forces the page to execute in STA mode. The runtime throws an exception if the compatibility tag is omitted and an STA component is referenced on the page.”
Using Windows Live Writer (WLW)? Writing posts takes you more time than you would like to invest? Looking for a ways to streamline your blogging? Want to be more productive and more efficient with blogging?
Try using Blog Post Template Plugin For Windows Live Writer.
Video: Blog Post Template Plugin for Windows Live Writer
Music by zeropage
I’ve created it for my personal needs and I thought it’d be good idea to share it with the blogoworld.
Installing the Plugin
No MSI mess – pure XCOPY “install”. Two files:
Using the Plugin
To use the plugin just pick it from Insert menu and you are done. It is like Word template for resume or Visual Studio template for Web Projects. How would look your day if you’d need to write resume from scratch or Web Projects in Notepad?
Editing your template
To edit the default tempalte that comes with the downlad just open template.txt file that is located in WLW’s installation folder and change it to whatever you like it. I use WLW to edit is then open Source pane, copy and paste it into Template.txt.
Try it
Go ahead and give it a shot – try Blog Post Template Plugin For Windows Live Writer. Drop me a line in case you like it, drop me another in case you don’t. Let me know what should I improve to make sure you love it.
Have fun. BTW, this post was created with the plugin.
Security Warning
Do not accept templates from untrusted sources - of course you can trust me…:). WLW renders the text as is so if someone sends you template with JavaScript in it, WLW will happily execute it. The code might pop up funny balloons, or do bad things. To make sure the Template is harmless open it in Notepad and look for “Script” blocks or funky URL’s (search for “href”).