/usr/lib/python3/dist-packages/eventlet/pools.py is in python3-eventlet 0.19.0-6.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | from __future__ import print_function
import collections
from contextlib import contextmanager
from eventlet import queue
__all__ = ['Pool', 'TokenPool']
class Pool(object):
"""
Pool class implements resource limitation and construction.
There are two ways of using Pool: passing a `create` argument or
subclassing. In either case you must provide a way to create
the resource.
When using `create` argument, pass a function with no arguments::
http_pool = pools.Pool(create=httplib2.Http)
If you need to pass arguments, build a nullary function with either
`lambda` expression::
http_pool = pools.Pool(create=lambda: httplib2.Http(timeout=90))
or :func:`functools.partial`::
from functools import partial
http_pool = pools.Pool(create=partial(httplib2.Http, timeout=90))
When subclassing, define only the :meth:`create` method
to implement the desired resource::
class MyPool(pools.Pool):
def create(self):
return MyObject()
If using 2.5 or greater, the :meth:`item` method acts as a context manager;
that's the best way to use it::
with mypool.item() as thing:
thing.dostuff()
The maximum size of the pool can be modified at runtime via
the :meth:`resize` method.
Specifying a non-zero *min-size* argument pre-populates the pool with
*min_size* items. *max-size* sets a hard limit to the size of the pool --
it cannot contain any more items than *max_size*, and if there are already
*max_size* items 'checked out' of the pool, the pool will cause any
greenthread calling :meth:`get` to cooperatively yield until an item
is :meth:`put` in.
"""
def __init__(self, min_size=0, max_size=4, order_as_stack=False, create=None):
"""*order_as_stack* governs the ordering of the items in the free pool.
If ``False`` (the default), the free items collection (of items that
were created and were put back in the pool) acts as a round-robin,
giving each item approximately equal utilization. If ``True``, the
free pool acts as a FILO stack, which preferentially re-uses items that
have most recently been used.
"""
self.min_size = min_size
self.max_size = max_size
self.order_as_stack = order_as_stack
self.current_size = 0
self.channel = queue.LightQueue(0)
self.free_items = collections.deque()
if create is not None:
self.create = create
for x in range(min_size):
self.current_size += 1
self.free_items.append(self.create())
def get(self):
"""Return an item from the pool, when one is available. This may
cause the calling greenthread to block.
"""
if self.free_items:
return self.free_items.popleft()
self.current_size += 1
if self.current_size <= self.max_size:
try:
created = self.create()
except:
self.current_size -= 1
raise
return created
self.current_size -= 1 # did not create
return self.channel.get()
@contextmanager
def item(self):
""" Get an object out of the pool, for use with with statement.
>>> from eventlet import pools
>>> pool = pools.TokenPool(max_size=4)
>>> with pool.item() as obj:
... print("got token")
...
got token
>>> pool.free()
4
"""
obj = self.get()
try:
yield obj
finally:
self.put(obj)
def put(self, item):
"""Put an item back into the pool, when done. This may
cause the putting greenthread to block.
"""
if self.current_size > self.max_size:
self.current_size -= 1
return
if self.waiting():
self.channel.put(item)
else:
if self.order_as_stack:
self.free_items.appendleft(item)
else:
self.free_items.append(item)
def resize(self, new_size):
"""Resize the pool to *new_size*.
Adjusting this number does not affect existing items checked out of
the pool, nor on any greenthreads who are waiting for an item to free
up. Some indeterminate number of :meth:`get`/:meth:`put`
cycles will be necessary before the new maximum size truly matches
the actual operation of the pool.
"""
self.max_size = new_size
def free(self):
"""Return the number of free items in the pool. This corresponds
to the number of :meth:`get` calls needed to empty the pool.
"""
return len(self.free_items) + self.max_size - self.current_size
def waiting(self):
"""Return the number of routines waiting for a pool item.
"""
return max(0, self.channel.getting() - self.channel.putting())
def create(self):
"""Generate a new pool item. In order for the pool to
function, either this method must be overriden in a subclass
or the pool must be constructed with the `create` argument.
It accepts no arguments and returns a single instance of
whatever thing the pool is supposed to contain.
In general, :meth:`create` is called whenever the pool exceeds its
previous high-water mark of concurrently-checked-out-items. In other
words, in a new pool with *min_size* of 0, the very first call
to :meth:`get` will result in a call to :meth:`create`. If the first
caller calls :meth:`put` before some other caller calls :meth:`get`,
then the first item will be returned, and :meth:`create` will not be
called a second time.
"""
raise NotImplementedError("Implement in subclass")
class Token(object):
pass
class TokenPool(Pool):
"""A pool which gives out tokens (opaque unique objects), which indicate
that the coroutine which holds the token has a right to consume some
limited resource.
"""
def create(self):
return Token()
|