Geeks With Blogs
On the Ledge The general evolution (and occasional regression) of a .NET developer

You guys have heard the song "Synchronicity 2," right?  Am I the only person who thinks Sting did that song for his own amusement?  Cackling in his lush, vaguely European voice at the fans scrambling to figure out the deeper meaning between a harried husband going through his day and the Loch Ness Monster getting his killing on.  I can just see him laughing atop his enormous piles of money as people make connections with Carl Jung and nod their heads sagely at the unique, but highly apt, metaphor.  Ah, Sting, is there anything you won't do?

Anyway, part of what I had to do to enhance the Proxy's performance is make the logging asynchronous.  In other words, we wanted the application to log something to the database, but not wait until that operation was complete before moving on.  One way to do this is by having the logging process run in its own thread.  The main application (in the main thread) hits the logging method, and it spins a new thread to run that code in while continuing on down the main thread.  When that spawned thread completes is of no consequence to the application.  So, if you can run it in its own process, this can speed up your application, because it isn't waiting around for stuff that it really doesn't need in order to finish.

After a few trials, we decided only to do this with logging the request and the response to the database.  The gains from making the log file logging asynchronous were both insignificant and inconsistent.

This is the first time I actually got into multi-threading.  I can't say I liked it very much, at first, but once I got to know my way around a bit, I can see that, in some applications, it can be an invaluable performance tool.

Some of you may already be thinking about things like BeginInvoke, but here's the thing I came to learn: virtually everything the .NET Framework provides for asynchronous threading involves using the ThreadPool under the hood.

The ThreadPool is a managed collection of threads which, in theory, allows the server to manage threads more efficiently.  So, a method like BeginInvoke works because it can receive notifications from the ThreadPool and hit callback functions, etc.

The problem is that the ThreadPool has a maximum number, and we wanted theoretically unlimited growth.  If we're getting several Flumphs a second and the database operations aren't keeping pace, you'll run into a large number of threads very quickly, at least for a time.  So, it looked like simply spawning another Thread without any fancy-schmancy asynchronicity baked into it was the way to go.

It's important to note, if you didn't already know, that threads by default will run parallel with the main thread.  So you don't have to do anything special to make them asynchronous.  It's just that the asynchronous stuff the Framework provides gives you a lot of flexible options, and probably has performance benefits, although I don't know that for a fact.

The syntax for creating a new thread and executing it is pretty simple.  First, code your method that you want to do something just like you usually would.

public static void DoStuff() 

  Console.Write("Throw open ya house!");
}

 

Then, in your code, you create your thread and pass it your method.

Thread myNewThread = new Thread(DoStuff); 

 

Technically, what you're doing is creating a delegate (an object in your program that represents a method) and passing that to the new thread.  The line above is just a shorthand way of doing it.  You could still actually type out the code to create a delegate for the DoStuff method and pass it to thread.  In fact, you can even create your delegate right there in the thread constructor, complete with the code that it represents.

Also, I used a static method, but it doesn't have to be static.  You could just as easily pass in myObject.SomeMethod.

When you want your new thread to kick off, it's as simple as:

myNewThread.Start();

 

Whatever delegate has been passed to your thread, you will execute that code in its own, separate thread parallel to the execution of the rest of your main code, which will continue chugging merrily along its way.  There are ways to wait for the new thread to finish, and I'll cover that when I get to our use of threads for processing responses.

Simple, eh?

Well, there might be a complication.  When you look at that line of code that creates a new thread, do you notice anything about the method we pass to it?  More specifically, do you notice the absence of anything?  Parenthesis, right?  No big deal in this case, but it's a plenty big deal if you want to pass parameters.

To cope with this, I created classes that had settable fields.  These classes also had the method that would be executed by the thread, and this method would simply access the class properties for its data.

For instance, I created a ResponseLogThread class.  It has three, private fields:

private readonly string _header; 
private readonly string _body;
private readonly Guid _requestId;

 

These fields are set in the constructor:

public ResponseLogThread(Guid requestId, string header, string body) 
{
  _header = header;
  _body = body;
  _requestId = requestId;
}

 

And then I have a method that is the code I want the thread to run:

public void ExecuteLogResponse() 
{
  ... writes info to database ...
}

 

Note that the method receives no parameters, but it doesn't need to.  The code just uses the values in _header, _body, and _requestId for its arguments.

Back in my main code, when I'm ready to create and execute my thread.  I first create an instance of ResponseLogThread that holds the values I want to "pass in," and then I create my new thread, passing it the ExecuteLogResponse method, like so:

ResponseLogThread responseLogThread = new ResponseLogThread(_requestId, response.Header, response.BodyStr);
Thread responseLogExecutionThread = new Thread(responseLogThread.ExecuteLogResponse);
responseLogExecutionThread.Start();

 

(You can see my proclivity for verbose names - and, no, BodyStr is not my invention.  It would probably be more like StringThatContainsTheBodyTextOfTheResponse or some other stupidity if I'd done it.)

The first line creates my object and sets its fields; the thread executes its method that refers to those properties.  It works great.

There are probably better ways to architect this solution, but this way works great, so suck it.

No, just kidding.  I'd love to hear other ways or more elegant ways that people do this.  Like I said, I'm new to it.  But it is also true that this does work great and it did buy us some nice performance gains.  If you have "side operations" in your code, you might consider doing something like this to run them in their own thread and see if it buys you some speed, too.

Posted on Thursday, September 24, 2009 1:18 PM How-To , Proxy | Back to top


Comments on this post: Asynchronicity, Too

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © ledge | Powered by: GeeksWithBlogs.net