dqd_threadpool
This is dqd_threadpool
release 1.1.
The dqd_threadpool
module manages a pool of worker
threads and a job queue. Client threads submit Tcl scripts to the
job queue and wait for the results. Worker threads pull jobs off the
queue, execute the scripts, and post the results for the clients to
retrieve.
This module should work with AOLserver 3.0 or later, but I have only tested it with AOLserver 3.2.
Set environment variable INST
to the location
where you installed AOLserver. Your AOLserver binary should be in
$INST/bin
.
In the dqd_threadpool
directory, run make
install
. This will compile the module and copy it to the
AOLserver installation. You must have write permission on
$INST/bin
to install the module.
To configure a thread pool, you must load the
dqd_threadpool
module:
ns_section ns/server/server1/modules ns_param mypool dqd_threadpool.so
This creates a thread pool named mypool
. You may
create several thread pools by loading the module repeatedly:
ns_section ns/server/server1/modules ns_param bookpool dqd_threadpool.so ns_param moviepool dqd_threadpool.so
This creates two thread pools, named bookpool
and moviepool
.
Let's say you want to write a simple book price comparison site. When a user types in an ISBN, you will use ns_httpget to look up the price of the book at several online bookstores.
The simplest approach is to call ns_httpget for each bookstore one at a time However, it takes time for the HTTP requests and responses to travel over the network, and each bookstore will take some time to look up the book and create the page to send back. It would be better to query all the bookstores simultaneously. A thread pool makes that easy.
Suppose you have configured bookpool
as a thread
pool. Then you can submit one job to the pool for each bookstore:
Nowset jobs {} lappend jobs [dqd_threadpool create bookpool [list amazon_lookup $isbn]] lappend jobs [dqd_threadpool create bookpool [list bn_lookup $isbn]] lappend jobs [dqd_threadpool create bookpool [list 1bookstreet_lookup $isbn]] lappend jobs [dqd_threadpool create bookpool [list wordsworth_lookup $isbn]]
$jobs
is the list of job ids. Next, you need
to wait for each job to complete. Each time a job completes,
you need to get its results and process them.
while {[llength $jobs] > 0} { # The wait command will return a list of two sublists. set pair [dqd_threadpool wait bookpool $jobs] # The first sublist is the list of job ids that have completed. set finished [lindex $pair 0] # The second sublist is the list of job ids that have not completed. set remaining [lindex $pair 1] foreach job $finished { set pair [dqd_threadpool get bookpool $job] set code [lindex $pair 0] set result [lindex $pair 1] if {$code == 1} { # Error. # Process error message here.... } else { # Success. # Process result here... } } # Continue looping until there are no remaining jobs. set jobs $remaining }
The complete source for this example is in the
examples/book
subdirectory. After installing the
dqd_threadpool
module, you can run the
example using this command:
/usr/local/aolserver/bin/nsd -ft examples/book/nsd.tcl
Then connect to http://localhost:10080/.
nscache
With dqd_threadpool
You can use the nscache
module to improve performance further.
In the book price comparison example, you would keep a cache of the responses from each bookstore for each ISBN. For each bookstore, you see if the cache already has the price for the book at that store. If not, then you queue a job to get and cache that store's price.
set jobs {} foreach bookstore {amazon bn 1bookstreet wordsworth} { set key "$bookstore.$isbn" if {[ns_cache get bookprices $key result]} { # Process result here... } else { lappend jobs [dqd_threadpool create bookpool \ [list ns_cache eval bookprices $key \ [list ${bookstore}_lookup $isbn]]] } }
Then you wait for any queued jobs to complete and process the results, as in the non-caching case.
The complete source for this example is in the
examples/book-cache
subdirectory. After installing
the dqd_threadpool
and nscache
modules, you can run the example using this command:
/usr/local/aolserver/bin/nsd -ft examples/book-cache/nsd.tcl
Then connect to http://localhost:10081/.
To create a threadpool named X
, load the
module by putting these lines in your configuration file:
ns_section ns/server/yourserver/modules ns_param X dqd_threadpool.so
If the configuration contains a section named
ns/server/yourserver/module/X
,
then the module will read parameters from that section.
The module understands these parameters:
MaxThreads
Default: 4
MinThreads
Default: 0
MaxIdle
MaxIdle
seconds without running a job,
and there are more than MinThreads
threads in the pool, then the thread will exit.
Setting
MaxIdle
to zero disables the timer, so threads
in the pool never exit.
Default: 30 (seconds)
MaxSize
create
or detach
, the command
checks the total size of the jobs. If the new job would
make the total exceed MaxSize
, then the
command blocks until enough jobs complete to make room for
the new job.
If a single job's size exceeds
MaxSize
, then create
or
detach
will block until the queue is completely
empty.
Setting MaxSize
to zero disables the limit.
Default: 0 (disabled)
Trace
on
will make the module emit various
messages about thread lifecycles and queue operations.
Default: off
dqd_threadpool
Command
dqd_threadpool create pool script
create
subcommand creates a new job.
Script
is added to the job queue for
pool
. The command returns a numeric job
id which can later be used to retrieve the result of the
script's execution.
You must eventually call get
on the
returned job id. The return value of the script will be
stored in memory until you do.
dqd_threadpool wait pool jobid-list
wait
subcommand waits for zero or more
jobs on pool
's job queue to complete.
Jobid-list
is a list of job ids
previously returned by the create
subcommand
for the same pool. As soon as any of the jobs in the list
completes, wait
returns a list with two
sublists. The first sublist contains the ids of any
completed jobs in the original list. The second sublist
contains the ids of the remaining incomplete jobs.
Wait
silently removes invalid job ids. The
invalid ids will not be included in either of the returned
sublists.
dqd_threadpool get pool jobid
get
subcommand retrieves the result of
a completed job. If job jobid
is invalid or
has not completed, get
raises an error. Otherwise,
get
returns a list of two elements. The first
element is the return code from the job. The second element is
the return value from the job. Typically a job script ends with a
return
statement like this:
In this case, the return code isreturn some-value
2
and the
return value is some-value
. If the
script raised an error, the return code will be
1
and the return value will be the error
message.
Get
can only be called once (successfully) for
each job id. Once get
has returned the result
of a job, the job id becomes invalid.
dqd_threadpool detach pool script
detach
subcommand creates a new
job, like the create
subcommand. However,
detach
does not return a job id. It is not
possible to retrieve the result of
script
using the normal
wait/get
mechanism. Use detach
if
you wish to run a job but you do not need the result and do
not wish to leak memory.
$Header: /u/cvsroot/nsd-modules/dqd_threadpool/index.html,v 1.6 2004/10/16 02:51:54 mayoff Exp $