1 from __future__ import print_function
4 from contextlib import contextmanager
6 from eventlet import queue
9 __all__ = ['Pool', 'TokenPool']
14 Pool class implements resource limitation and construction.
16 There are two ways of using Pool: passing a `create` argument or
17 subclassing. In either case you must provide a way to create
20 When using `create` argument, pass a function with no arguments::
22 http_pool = pools.Pool(create=httplib2.Http)
24 If you need to pass arguments, build a nullary function with either
27 http_pool = pools.Pool(create=lambda: httplib2.Http(timeout=90))
29 or :func:`functools.partial`::
31 from functools import partial
32 http_pool = pools.Pool(create=partial(httplib2.Http, timeout=90))
34 When subclassing, define only the :meth:`create` method
35 to implement the desired resource::
37 class MyPool(pools.Pool):
41 If using 2.5 or greater, the :meth:`item` method acts as a context manager;
42 that's the best way to use it::
44 with mypool.item() as thing:
47 The maximum size of the pool can be modified at runtime via
48 the :meth:`resize` method.
50 Specifying a non-zero *min-size* argument pre-populates the pool with
51 *min_size* items. *max-size* sets a hard limit to the size of the pool --
52 it cannot contain any more items than *max_size*, and if there are already
53 *max_size* items 'checked out' of the pool, the pool will cause any
54 greenthread calling :meth:`get` to cooperatively yield until an item
58 def __init__(self, min_size=0, max_size=4, order_as_stack=False, create=None):
59 """*order_as_stack* governs the ordering of the items in the free pool.
60 If ``False`` (the default), the free items collection (of items that
61 were created and were put back in the pool) acts as a round-robin,
62 giving each item approximately equal utilization. If ``True``, the
63 free pool acts as a FILO stack, which preferentially re-uses items that
64 have most recently been used.
66 self.min_size = min_size
67 self.max_size = max_size
68 self.order_as_stack = order_as_stack
70 self.channel = queue.LightQueue(0)
71 self.free_items = collections.deque()
72 if create is not None:
75 for x in range(min_size):
76 self.current_size += 1
77 self.free_items.append(self.create())
80 """Return an item from the pool, when one is available. This may
81 cause the calling greenthread to block.
84 return self.free_items.popleft()
85 self.current_size += 1
86 if self.current_size <= self.max_size:
88 created = self.create()
90 self.current_size -= 1
93 self.current_size -= 1 # did not create
94 return self.channel.get()
98 """ Get an object out of the pool, for use with with statement.
100 >>> from eventlet import pools
101 >>> pool = pools.TokenPool(max_size=4)
102 >>> with pool.item() as obj:
103 ... print("got token")
116 """Put an item back into the pool, when done. This may
117 cause the putting greenthread to block.
119 if self.current_size > self.max_size:
120 self.current_size -= 1
124 self.channel.put(item)
126 if self.order_as_stack:
127 self.free_items.appendleft(item)
129 self.free_items.append(item)
131 def resize(self, new_size):
132 """Resize the pool to *new_size*.
134 Adjusting this number does not affect existing items checked out of
135 the pool, nor on any greenthreads who are waiting for an item to free
136 up. Some indeterminate number of :meth:`get`/:meth:`put`
137 cycles will be necessary before the new maximum size truly matches
138 the actual operation of the pool.
140 self.max_size = new_size
143 """Return the number of free items in the pool. This corresponds
144 to the number of :meth:`get` calls needed to empty the pool.
146 return len(self.free_items) + self.max_size - self.current_size
149 """Return the number of routines waiting for a pool item.
151 return max(0, self.channel.getting() - self.channel.putting())
154 """Generate a new pool item. In order for the pool to
155 function, either this method must be overriden in a subclass
156 or the pool must be constructed with the `create` argument.
157 It accepts no arguments and returns a single instance of
158 whatever thing the pool is supposed to contain.
160 In general, :meth:`create` is called whenever the pool exceeds its
161 previous high-water mark of concurrently-checked-out-items. In other
162 words, in a new pool with *min_size* of 0, the very first call
163 to :meth:`get` will result in a call to :meth:`create`. If the first
164 caller calls :meth:`put` before some other caller calls :meth:`get`,
165 then the first item will be returned, and :meth:`create` will not be
166 called a second time.
168 raise NotImplementedError("Implement in subclass")
175 class TokenPool(Pool):
176 """A pool which gives out tokens (opaque unique objects), which indicate
177 that the coroutine which holds the token has a right to consume some