Project Name | Stars | Downloads | Repos Using This | Packages Using This | Most Recent Commit | Total Releases | Latest Release | Open Issues | License | Language |
---|---|---|---|---|---|---|---|---|---|---|
Requests Threads | 331 | 4 years ago | 7 | Python | ||||||
🎭 Twisted Deferred Thread backend for Requests. | ||||||||||
Crochet | 221 | 81 | 14 | 2 years ago | 18 | May 10, 2021 | 19 | mit | Python | |
Crochet: use Twisted anywhere! | ||||||||||
G Firefly | 129 | 5 years ago | 5 | Python | ||||||
Firefly's gevent version, with better perfromance than its previous twisted version | ||||||||||
Pyfire | 39 | 33 | 9 years ago | 3 | November 02, 2011 | 3 | mit | Python | ||
A python implementation of the Campfire API | ||||||||||
Scrapy Flask | 34 | 5 years ago | 1 | Python | ||||||
Execute Scrapy spiders in a Flask web application | ||||||||||
Featdjango | 7 | 9 years ago | Python | |||||||
Threaded container for django application, integration with twisted asynchronous framework | ||||||||||
Requests Twisted | 6 | 6 years ago | 1 | zlib | Python | |||||
Twisted adapter for the requests library | ||||||||||
Thimble | 5 | 1 | 1 | 4 years ago | 3 | March 07, 2016 | 3 | other | Python | |
A Twisted thread-pool based wrapper for blocking APIs. | ||||||||||
Sqlmix | 5 | 4 months ago | 3 | July 23, 2017 | 1 | gpl-3.0 | Python | |||
Database-agnostic SQL frontend for Python | ||||||||||
Twisted Django | 4 | 9 years ago | isc | Python | ||||||
Twisted+Django integration layer |
A thimble is a tool for playing with needle and thread safely. This library, thimble, wraps objects that have a blocking API with a non-blocking, Twisted-friendly Deferred API by means of thread pools.
The main object you're interested in is thimble.Thimble
. It takes a
thread pool, a blocking object, and a list of method names that you
would like to defer to the thread pool.
Here's our example blocking object:
>>> class Car(object):
... wheels = 4
... def drive_to(self, location):
... # Assume the real implementation blocks.
... return "driven to {0}".format(location)
>>> car = Car()
For demonstration purposes, we'll use a test doubles for the thread pool and reactor; in real code, you'll want to use the real thing.
>>> from thimble.test.util import FakeThreadPool, FakeReactor
>>> pool = FakeThreadPool()
>>> reactor = FakeReactor()
The pool hasn't been started yet. (We'll see why that matters in a minute.)
>>> pool.started
False
Create a Thimble
:
>>> from thimble import Thimble
>>> car_thimble = Thimble(reactor, pool, car, ["drive_to"])
When accessing a method named in the list, you get an object wrapping it instead. Calling it returns a Deferred. Any arguments passed are passed verbatim to the wrapped method.
>>> def print_(s):
... # can't use from __future__ import print_function because of a
... # doctest limitation :-(
... print s
>>> d = car_thimble.drive_to("work").addCallback(print_)
driven to work
This Deferred has already fired synchronously, because we're using a fake thread pool and reactor.
You can access other attributes of the wrapped object directly on the
Thimble
:
>>> car.wheels
4
If the thread pool that you pass to a Thimble
hasn't been started
yet when it first tries to use it, the Thimble
will start it and
schedule its shutdown. If you pass a thread pool that was already
started, you are responsible for its shutdown. In this case, the
thread pool was not started yet, so Thimble
started it for you:
>>> pool.started
True
Shut down the reactor, and the reactor will ask the thread pool to stop right before shutting down itself.
>>> reactor.stop()
>>> pool.started
False
You can choose to use the reactor thread pool, or create your own thread pool.
Using the reactor thread pool is potentially a bad idea. The reactor thread pool is shared between a lot of software by default, and is also used for DNS resolution. If your software blocks all the available threads in the pool (either by accident or because of a bug), that affects DNS resolution, which in turn can affect many other systems; if it doesn't affect those systems directly (because they, too, want to use the reactor thread pool).
It's probably most reliable to have a dedicated thread pool per application, for two reasons:
Unfortunately, shared global state is pretty much how you do it:
from twisted.python.threadpool import ThreadPool _the_thread_pool = _ThreadPool()
See the documentation for the ThreadPool class for more details; it allows you to specify a minimum and maximum number of threads. The default values are probably pretty reasonable.
The number of threads you specify your thread pool to have is the number of threads that can try to access your object concurrently. it's up to you to make sure that the object is actually thread safe.
If you would like to provide a non-blocking API to an object that
isn't thread safe, you can just limit the number of threads in the
thread pool to 1, causing fully synchronized access. Keep in mind that
attribute accesses for any attribute name that isn't in the
blocking_methods
list will still be performed synchronously by the
calling thread.
While subclassing Thimble
may accidentally work, it is not
recommended. I reserve the right to change the implementation in a way
that might break that: for example, by introducing a metaclass.
It's probably better to write a small utility function that either
constructs a new Thimble
that uses a shared thread pool, or always
returns the same thimble.
Thimble uses SemVer.
.gitignore
Initial public release.