Now that we have covered the basics of sending data into and getting data out of ColdFusion 8's new CFThread-launched processing threads, let's examine some places where they can be used. For this post, we are going to concenrate on utilizing CFThread to speed up page processing even if we need all threads to finish processing in the same request.
Often times, while there is a single, overall goal for a page request, that page request is divided up into chunks of code that may be run independently. Take for example grabbing search results from Google.com. Imagine we wanted to grab the first 1,000 search results for his buffness, Vin Diesel, using ColdFusion's CFHttp tag. Google only allows you to grab a max of a 100 results in a single request, so in order to get 1,000 results, it means we have to make 10 sepparate CFHttp requests, each grabbing the next 100 results.
Now, each of those 100 results relates to the overall goal of the page, but does one set of 100 really have anything to do with the next set of 100? Sure, they have to be in some sort of order, but would it even matter which order we made our requests in, so long as the final results were the same?
Absolutely not. But, using traditional ColdFusion code, we have no other option but to make one CFHttp request and then wait for it to finish before making our next CFHttp request. By the very nature of our single-threaded request (well, technically multi-threaded request since CFHttp fires a new process), each CFHttp call is directly tied to the next via processing availability.
This syncronous processing is not as fast as it can be. Take a look at this traditional CFHttp code:
Launch code in new window » Download code as text file »
If we run the above code a few times, we get the output:
We Got 1000 Results in 4.83 seconds using standard CFHttp
We Got 1000 Results in 4.92 seconds using standard CFHttp
We Got 1000 Results in 12.97 seconds using standard CFHttp
We Got 1000 Results in 4.11 seconds using standard CFHttp
We Got 1000 Results in 7.11 seconds using standard CFHttp
As you can see, the total page processing time took anywhere from 4.11 seconds to almost 13 seconds.
Now that ColdFusion 8 has introduced the new CFThread tag, we can break free of our single-threaded mind-set. No longer does independent code have to wait for other parts of the code to finish processing (as in our above example). In this next example, we are going to wrap each CFHttp call inside of its own CFThread tag. This will allow ColdFusion to launch a new, asycronous thread for each 100 results from Google.com:
Launch code in new window » Download code as text file »
Running the above code a few times, we get the output:
We Got 1000 Results in 0.79 seconds using CFHttp and CFThread
We Got 1000 Results in 0.69 seconds using CFHttp and CFThread
We Got 1000 Results in 0.72 seconds using CFHttp and CFThread
We Got 1000 Results in 0.63 seconds using CFHttp and CFThread
We Got 1000 Results in 3.44 seconds using CFHttp and CFThread
As you can see, the page processing time decreased dramatically - usually less than a second in total. So what's with the 3.44 second entry? ColdFusion 8's new CFThread tag requests that a new thread be launched to handle this code; however, the ColdFusion application server does not have an unlimitted number of threads at its disposal. Each CFThread tag requests a new thread. This thread request is then queued for processing. When a processing thread becomes available, it gets passed to the CFThread code for asyncronous processing (also, in our case, processing time is directly tied to the speed of Google.com to return results).
This is very important to undestand. Running parallel threads will only make your page run faster if parallel threads are available to be launched. If you have a server that is maxed out on page requests, wrapping code in CFThread might not have any affect at all (in that case, it might actually have a negative affect since the current page now has to wait for threads... but that is purely an uneducated hypothesis). However, since computers spend like 90% of their time waiting for user requests (at least that is what I hear about Personal Desktop Computers - probably not the same for web servers), it's more likely than not that running parallel threads using ColdFusion 8's CFThread will lead to dramatic page performance increases.
Also notice that after our CFHttp requests, we are explicitly requesting that the parent page wait for all the parallel threads to finish processing (and to join the page). Since these threads are all running in parallel, there is no guarantee that any one thread will have finished processing by the time the parent page reaches a certain line unless you explicitly wait for a named thread to finish. Mental note!
Just remember that since these threads are running in parallel (probably), you must be very careful about making cross-thread references. Unless you explicitly wait for one thread to finish, there is no guarantee that a value set in one thread will be available in another at any given time. And, as always, if you think a negative race condition might apply, please wrap variable access and modification code inside of CFLock tags.
Download Code Snippet ZIP File
Comments (5) | Post Comment | Ask Ben | Permalink | Other Searches | Print Page
Learning ColdFusion 8: CFThread Part III - Set It And Forget It
Fusion Authority Quarterly Update Filling In The Gaps
@Ben:
Don't forget that the "name" attribute can take a list of threads to join. So in your loop code where you're creating the threads, you could append the name of the thread to a list and just do something like:
<cfthread
action="join"
name="#lstThreads#"
/>
Posted by Dan G. Switzer, II on Jun 4, 2007 at 2:27 PM
PS - I've also filed Enhanced #69430 with Adobe to allow the name attribute to be optional, so w/out a "name" attribute, it would just join all threads in the current page template together. :)
Posted by Dan G. Switzer, II on Jun 4, 2007 at 2:28 PM
@Dan,
Good catch. I forgot to mention that in my run-down. As for your enhancement, that would be awesome! I figure this is a use-case that will be used quite often and would help tremendously.
Posted by Ben Nadel on Jun 4, 2007 at 2:52 PM
Just in case you have not noticed, you can set the maximum number of cfthreads that can run parallely in the server, from administrator. That is the max size of thread pool dedicated to run cfthreads. By default it is set to 10 .
Another point to note is that if you specify a large number for it lets say 50, it does not mean all the 50 threads will be running all the time. The pool is dynamic and it adjusts according to the load. So at peak load, it will go upto 50 and when there is no load, it can drop down to 1.
Rupesh
Adobe CF Team.
Posted by Rupesh Kumar on Jun 15, 2007 at 3:51 PM
@Rupesh,
Thanks for pointing that out. Right now, I am doing most of my testing on HostMySite.com, so I don't have Admin access. I installed the Beta on my desktop at home, but something went screwy with the install, and neither the CFIDE nor the CFDOCS folder seems to have installed in the Coldfusion8 folder. I was running CF7 at the time, so I don't know if that messed it up. I will probably uninstall and re-install or just try to install again.
I can't wait to turn on my per-application-setting so that I can play with the app-specific mappings :)
Posted by Ben Nadel on Jun 15, 2007 at 5:53 PM