Sie sind auf Seite 1von 4

<cffunction name="multiThreadDemo" access="public" returntype="struct">

<!--- This is what we do normally inside cffunction because of our


Framework, but you dont have to do it like this --->
<!--- Specify a local scope variable--->
<cfset var local = structNew()>
<!--- specify a result struct to use as a return variable --->
<cfset local.result = structNew()>

<!--- obviously, you might have this coming from somewhere different --->
<cfset local.ds = "theDatasource">

<!--- This is fed into the recordset-retrieving cfquery. -1 means all


records --->
<cfset local.maxRecordSetSize = -1>

<!--- This is the number of threads that you want to run at a time. We callt
he collection of threads a Spool.
This doesn't change any JRun or JVM settings, so be aware of
that. In other
words, if you have JVM setting that specifies a max of 10 threads
and you set the maxConcurrentThreads variable to 11 then only 10 will be
created to start with, there will then be a wait until the next
single thread is created --->
<cfset local.maxConcurrentThreads = 5>

<!--- This is the max number of records from your data query that will be
processed inside each thread. Think of it as the control
on how long you want each thread to run for. For a record set of
26471, I used a batch size of 200 with 5 concurrent threads --->
<cfset local.recordBatchSize = 200>

<!--- depends very much on the size of your record set and how much
processing you are going to do --->
<cfsetting requesttimeout="360">

<cfsavecontent variable="local.result.output">
<cfquery datasource="#local.ds#" name="local.data"
maxrows="#local.maxRecordsetSize#">
select fields
from tableName
</cfquery>

<!--- calculations to work out from/to --->


<cfset local.currentThreadNumber = 0>
<cfset local.recordStartPointAddition = 0>
<cfset local.totalNumberOfThreads = Ceiling(local.data.recordCount /
local.recordBatchSize)>
<!--- numberOfSpools is the number of sets of <maxConcurrentThreads>
threads that will be run--->
<cfset local.numberOfSpools = Ceiling(local.totalNumberOfThreads /
local.maxConcurrentThreads)>

<cfoutput><h1>#local.data.recordCount# records to
update</h1></cfoutput>

<cfloop from="1" to="#local.numberOfSpools#" index="local.spoolI">


<cfset local.threadList = "">
<cfoutput><h2>Spool #local.spoolI#</h2></cfoutput>

<cfloop from="1" to="#local.maxConcurrentThreads#"


index="local.threadI">
<cfset local.queryFrom = ((local.threadI-
1)*local.recordBatchSize)+1 + local.recordStartPointAddition>
<cfset local.queryTo = Min(local.queryFrom +
(local.recordBatchSize-1), local.data.recordCount)>

<!--- you create threads called 'thread<i>' where i is the


variable local.currentThreadNumber --->
<cfset local.currentThreadNumber =
local.currentThreadNumber + 1>
<!--- make sure you need to do something --->
<cfif local.queryFrom le local.queryTo>
<cfoutput>
<h3>Creating thread #local.currentThreadNumber#
running records #local.queryFrom# to #local.queryTo#</h3>
</cfoutput>

<!--- create and run the thread. Pass in the


parameters and data --->
<cfthread action="run"
name="thread#local.currentThreadNumber#" data="#local.data#"
queryFrom="#local.queryFrom#"
queryTo="#local.queryTo#"
>
<!--- it is all in the thread's local scope
anyway --->
<cfset local = structNew()>
<!--- anything with thread. as the scope can be
retrieved once the thread is Completed--->
<cfset thread.recordTotal = 0>
<cftry>
<cfloop query="attributes.data"
startrow="#attributes.queryFrom#" endrow="#attributes.queryTo#">
<!--- CUSTOM Processing Code Goes
Here --->
</cfloop>

<!--- keep running totals of how many


records have been processed --->
<cfset thread.recordTotal =
attributes.queryTo-attributes.queryFrom+1>
<cfcatch type="any">
<!--- errors need passing out of
the thread otherwise you end up clueless--->
<cfset thread.cfcatch = cfcatch>
</cfcatch>
</cftry>
</cfthread>

<!--- keep a record of what thread numbers have been


run during this Spool --->
<cfset local.threadList =
ListAppend(local.threadList, local.currentThreadNumber)>
</cfif>
</cfloop>
<cfif ListLen(local.threadList)>
<cfoutput><h6>Rejoin threads
#local.threadList#</h6></cfoutput>

<!--- Add up all the records-processed values from each


thread--->
<cfset local.threadRecordTotal = 0>
<cfloop list="#local.threadList#" index="local.threadI">
<cfset local.theThreadName = "thread#local.threadI#">
<!--- Wait for the thread to finish --->
<cfthread action="join"
name="#local.theThreadName#"/>

<cftry>
<!--- Weird way of getting thread value out,
but the trouble is threads are NOT structures. If anyone
has a better way of doing this,
please let me know!--->
<cfset local.theThreadTotal =
Evaluate('#local.theThreadName#.recordTotal')>
<cfset local.threadRecordTotal =
local.threadRecordTotal + local.theThreadTotal>

<!--- Make sure the thread is really dead--->


<cfthread action="terminate"
name="#local.theThreadName#"/>
<cfset "#local.theThreadName#" = "">

<cfif local.theThreadTotal eq 0>


<!--- this is likely to run if the thread
errored and exited --->
<cfoutput>
<p><strong>Thread
#local.theThreadName# doesn't seem to have done anything</strong></p>
<cfdump
var="#Evaluate('#local.theThreadName#')#">
</cfoutput>
</cfif>

<cfcatch type="any">
<cftry>
<cfdump var="#cfcatch#">
<cfdump
var="#Evaluate('#local.theThreadName#')#">
<cfcatch type="any">
<cfoutput><p>Unrecoverable
error on thread #local.theThreadName#</p></cfoutput>
</cfcatch>
</cftry>
</cfcatch>
</cftry>
</cfloop>

<cfoutput><h4>Spool #local.spoolI# looped through


#local.threadRecordTotal# records</h4><hr/></cfoutput>
<cfset local.recordStartPointAddition =
local.recordStartPointAddition + local.threadRecordTotal>
</cfif>
</cfloop>
</cfsavecontent>

<cfreturn local.result>
</cffunction>

Das könnte Ihnen auch gefallen