Programming, Python

Cool threads

Simple use

This is where CoolThreads shines. The simplest case is to write a function to do what you need in a thread. For example, let’s say you have a function called “myProc” that you want to run 1,000 copies of.

First, start the dispatcher, which is a single statement:

myQueue = CoolThreads('SampleQueue')

That creates a CoolThreads dispatcher and gives it the name SampleQueue. It’s a threaded Python object, so it is now in the background.

But wait, you say! A threaded Python object doesn’t do anything if you don’t call its start method.

That’s true, of course, but remember that object coding features inheritance. I wrote this class. It’s a reliable self-starter, inherited from… Look, I’m trying to find a job right now. Please give me some latitude in my wisecracks. CoolThreads calls its own start method so you don’t have to worry about it. There is nothing wrong about being a self-starter.

Next, create an instance of CoolThreadOp, informing it of the function to run, pass any arguments the called function will need, and hand the CoolThreadOp instance to CoolThreads.CTaddThread.

The target function needs to support the argument signature (*args, **kwargs), and will get a reference to the CoolThreads object as kwargs[‘CT’]. This allows the function access to a thread protected wrapper, logging, and other features of CoolThreads.

Here’s what it looks like to start an instance of our example myProc function:

myQueue.CTaddThread(CoolThreadOp(
                     'testthread-1',
                     CTrunFunction = 'myProc',
                     myProcKeyword1 = someparam,
                     anotherMyProcArg = 'something else'))

The keyword arguments for myProc are whatever myProc needs. In this example, myProcKeyword1 and anotherMyProcArg are just examples. You can pass non-keyword arguments through the CoolThreadOp constructor as well. Just list them first and make sure to pass CoolThreadOp’s arguments (like CTrunFunction) as keyword arguments – that’s where you name the argument and use an equals sign to set the argument’s value.

Once you’ve launched all the threads you need, wait for it to finish and conclude thread dispatching:

myQueue.CTwaitForComplete()

The CTwaitForComplete function waits for all worker threads to complete, terminates the CoolThreads instance, and triggers a dump of all deferred logging.

In a nutshell, launching 1000 copies of a function with 50 always active and capturing log output:

with open('queuelog.txt', 'wt') as logFile:
 myQueue = CoolThreads('SampleQueue', logFile, 50)
 for i in range(1000):
  myQueue.CTaddThread(f'test-{i}',
                      CoolThreadOp(
                       CTrunFunction = 'myProc',
                       **myProcCommands[i]))
 myQueue.CTwaitForComplete()

Pretty slick. In five lines you start threaded dispatching, launch a thousand copies of a thread always running 50 simultaneously, and terminate threaded processing.

For food for thought, a list called myProcCommands was assumed to contain dictionaries of keyword arguments for the launched threads.

Since we didn’t opt for chronological order, log entries will be grouped by thread for easy interpretation.

Each log entry, whether ordered chronologically or collated by thread, always includes the thread ID and a time stamp.


Let me know what you think, in the comments below, by email to carl@carlhaddick.com, or via the Get in Touch! link at the top of this page. Source to coolthreads.py and a nice detailed PDF document are available for download here.

Be sure to enable the table of contents pane in your PDF viewer for nice navigation through the documentation.