Earlier today I wrote a quick blog entry (CFTHREAD, Names, and Commas) about a bug I had with cfthread names. I mentioned that commas were not allowed in the thread name and that - probably - this was due to the use of the JOIN action allowing for a list of thead names to join together. Tony asked me why someone would use the JOIN action at all.
First off, what happens when you create a thread and don't do anything else?
2 <cfset sleep(10000)>
3 <cflog file="tdemo" text="All done, baby.">
4 </cfthread>
5
6 <cfdump var="#cfthread#">
In this demo I create a thread. It sleeps for 10 seconds and then writes to a log file. Outside of the thread I dump the cfthread scope. (Everyone knows that exists, right? It gives you metadata about threads created during the request.) Running this we can see that even though the page ended, the thread is still running:

If you check your log files a bit later, you will see that the thread eventually did end and write to the log. In essence, this process is a "Fire and Forget" thread. You start the slow process and don't need to worry about waiting for it to end. A real world example could be starting a slow running stored procedure that performs a database backup.
But what about cases where you do need to wait for a result? Imagine an RSS aggregator. You want to hit N RSS feeds and take each result and add it to a large query. (Oh, I've got a CFC for that if you want something like that.) In this case, you want each thread to handle doing the slow process, but you want to wait for them all to finish before proceeding.
Consider this modified example:
2 <cfloop index="x" from="1" to="10">
3 <cfset name = "find more cowbell #x#">
4 <cfset threadlist = listAppend(threadlist, name)>
5 <cfthread name="#name#">
6 <cfset sleep(10000)>
7 <cflog file="tdemo" text="All done with #thread.name#, baby.">
8 </cfthread>
9 </cfloop>
10
11 <cfthread action="join" name="#threadlist#" />
12 <cfdump var="#cfthread#">
In this example, I've added a loop so that I can create 10 threads. Notice that I store the name in a list. This lets me run the join action at the end. Now if you run the file you will notice it takes 10 seconds to run. This represents the JOIN line waiting for the threads to end. Because they run in parallel, I don't have to wait 100 seconds, but just 10. Obviously most real world applications won't have a nice precise timeframe like that. Now if you look at the dump, you can see that they completed:

So the short answer is simply - it depends. If you need to work with the result in the same request, then use the join. If not, don't worry about it.
Comment 1 written by tony weeg on 18 May 2009, at 1:50 PM
i use cfthread for a lot of things now, just hadnt used the join parameter yet. thanks!
Comment 2 written by Raymond Camden on 18 May 2009, at 1:51 PM
Comment 3 written by todd sharp on 18 May 2009, at 1:57 PM
Comment 4 written by Raymond Camden on 18 May 2009, at 1:59 PM
<cf_juvenile>
"pulled it out" - thats what she said
</cf_juvenile>
Comment 5 written by tony weeg on 18 May 2009, at 2:02 PM
ok, some other things changed to bring that down from 4hrs to 30 minutes but this feature helped them most!
Comment 6 written by todd sharp on 18 May 2009, at 2:07 PM
Comment 7 written by Andy Sandefer on 18 May 2009, at 2:07 PM
The need for join seems very logical to me. Imagine that we kick off a process that is going to execute several different things server side (think transactional database). We would probably use this in combination with cftransaction but basically you could use the join action when you have cascading activities happening as in my application needs to do things in the database within a certain order or I'll violate the referential integrity of the system if certain records are not created in the proper chain of events (sequencing). If the user clicks a button that kicks off this chain of events that occurs on the database server then we probably don't want to make them sit around and wait until the whole mess is finished processing until we give them back the browser - so enter in cfthread with join power.
Comment 8 written by Eric on 18 May 2009, at 2:29 PM
Anyway, shameless plug here:
http://www.ownster.com
Works perfectly!
Comment 9 written by Raymond Camden on 18 May 2009, at 3:13 PM
Comment 10 written by Ryan on 18 May 2009, at 3:19 PM
Building a Zip Code Proximity Search with ColdFusion
http://coldfusion.sys-con.com/node/154258
Using CFThread would probably be handy when implementing a lookup like this, particularly if there was some obscure reason you wanted to solve for distance using all 4 methods described in his article. Computing the distance between a given zip code and a large number of locations (even as few as 100) would normally fall under the 'serial' way of guessing how long it would take. Using threads would make it parallel (though possibly stressing out your server if you spawned too many threads at once).
I assume you would want to join your threads at the end to show your results in a table or show the 1 location with the least distance to your primary zip code.
Comment 11 written by Andy Sandefer on 18 May 2009, at 3:21 PM
@Ray - You need to move to a strictly cash only policy, please for the sake of all that is good! Then I can always get by on the "It's only money" phrase that makes people feel materialistic if they don't instantly agree with you.
Comment 12 written by Raymond Camden on 18 May 2009, at 3:24 PM
Comment 13 written by Andy Sandefer on 18 May 2009, at 3:25 PM
That may be a good article but I can't click on your link because the SysCon will try to poison my mind with loud auto-playing commercials about Windows and Visual Studio and if that doesn't kill me than that Turkish guy from Ulitzerkaselzer probably will.
Comment 14 written by jonathan on 19 May 2009, at 9:18 AM
Question... I would be curious as to people's server performance issues with cfthread. Right now our box (multi cf instances on vm) only has one cpu and it's killing it. The process runs slower than on my local laptop (which is dual core) and freezes up every jrun instance. I even set the number of threads down to 5 and set the cfthread to low priority. That just makes it freeze up longer.
Turned off server monitor as well. We are pushing to get another cpu which may solve the problem. On my laptop i can run between 35-50 threads at a time without any issues
Comment 15 written by Brian on 19 May 2009, at 11:14 AM
Now, if I could just figure out how to do LDAP paged queries using CFLDAP (which i don't think I can -- seems I have to go right to the JVM), I could mightily improve the process. <sigh>
Comment 16 written by Don on 20 May 2009, at 11:49 AM
Here is my problem tho. How to display the results when they are ready but display something else while they are running. Somebody said this can be done with cfthread but I'm not sure.
Comment 17 written by Raymond Camden on 20 May 2009, at 11:53 AM
Comment 18 written by Don on 20 May 2009, at 11:58 AM
:)
Comment 19 written by Raymond Camden on 20 May 2009, at 12:18 PM
Comment 20 written by Sebastiaan on 21 August 2009, at 2:58 AM
I have the following challenge where I suspect CFTHREAD could come in handy.
In our CMS we update a record where the user has changed its documenttype. This change needs to be pushed to another database (say deltadatabase) so another system can import these changes. Now in the transaction to update the changed record in the CMS I've included a customtag that does the update to the deltadatabase. But the logic in this customtag calls the CMS to get its information. But this information has just been changed, so the customtag returns zero.
The challenge is to do the update to the deltadatabase and wait for this to have been processed completely before actually updating the record in the CMS. I have changed the transaction code in the CMS to post the old as well as the new documenttype, so I can use this as a trigger in the transaction that an extra update is necessary and that one process has to wait for the other to finish.
Am I making the challenge clear enough?
How to set up these threads? I'm a newbie to threads, just so you know ;-)
Comment 21 written by Don on 22 September 2009, at 2:20 PM
BUT I'm also now using a cfthread that does not join. Instead of waiting for a page to be called that runs this huge query, I go ahead and run it so the results are ready when the page is called.
However, there is also a place for a join. This app pulls data from 6 other applications and puts it all together. Right now the app does each one in sequence. Instead I'm working on the cfthread with the join at the end to put it all together in one shot.
Comment 22 written by Don on 22 September 2009, at 5:30 PM
Comment 23 written by Raymond Camden on 23 September 2009, at 3:54 PM
Comment 24 written by Don on 23 September 2009, at 4:38 PM
[Add Comment] [Subscribe to Comments]