Before you start using threads, make sure you do at the start of your program:
from twisted.python import threadable threadable.init()
This will make certain parts of Twisted thread-safe so you can use them safely. However, note that most parts of Twisted are not thread-safe.
Most code in Twisted is not thread-safe. For example,
writing data to a transport from a protocol is not thread-safe.
Therefore, we want a way to schedule methods to be run in the
main event loop. This can be done using the function twisted.internet.interfaces.IReactorThreads.callFromThread
:
from twisted.internet import reactor from twisted.python import threadable threadable.init(1) def notThreadSafe(x): """do something that isn't thread-safe""" # ... def threadSafeScheduler(): """Run in thread-safe manner.""" reactor.callFromThread(notThreadSafe, 3) # will run 'notThreadSafe(3)' # in the event loop
Sometimes we may want to run methods in threads - for
example, in order to access blocking APIs. Twisted provides
methods for doing so using the IReactorThreads API (twisted.internet.interfaces.IReactorThreads
).
Additional utility functions are provided in twisted.internet.threads
. Basically, these
methods allow us to queue methods to be run by a thread
pool.
For example, to run a method in a thread we can do:
from twisted.internet import reactor def aSillyBlockingMethod(x): import time time.sleep(2) print x # run method in thread reactor.callInThread(aSillyBlockingMethod, "2 seconds have passed")
The utility methods are not part of the twisted.internet.reactor
APIs, but are implemented
in twisted.internet.threads
.
If we have multiple methods to run sequentially within a thread, we can do:
from twisted.internet import threads def aSillyBlockingMethodOne(x): import time time.sleep(2) print x def aSillyBlockingMethodTwo(x): print x # run both methods sequentially in a thread commands = [(aSillyBlockingMethodOne, ["Calling First"], {})] commands.append((aSillyBlockingMethodTwo, ["And the second"], {})) threads.callMultipleInThread(commands)
For functions whose results we wish to get, we can have the result returned as a Deferred:
from twisted.internet import threads def doLongCalculation(): # .... do long calculation here ... return 3 def printResult(x): print x # run method in thread and get result as defer.Deferred d = threads.deferToThread(doLongCalculation) d.addCallback(printResult)
The thread pool is implemented by twisted.python.threadpool.ThreadPool
.
We may want to modify the size of the threadpool, increasing or decreasing the number of threads in use. We can do this do this quite easily:
from twisted.internet import reactor reactor.suggestThreadPoolSize(20)
The size of the thread pool defaults to a maximum of 10 threads. Be careful that you understand threads and their resource usage before drastically altering the thread pool sizes.