|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- # -*- coding: utf-8 -*-
- """
- kombu.async.semaphore
- =====================
-
- Semaphores and concurrency primitives.
-
- """
- from __future__ import absolute_import
-
- from collections import deque
-
- __all__ = ['DummyLock', 'LaxBoundedSemaphore']
-
-
- class LaxBoundedSemaphore(object):
- """Asynchronous Bounded Semaphore.
-
- Lax means that the value will stay within the specified
- range even if released more times than it was acquired.
-
- Example:
-
- >>> from future import print_statement as printf
- # ^ ignore: just fooling stupid pyflakes
-
- >>> x = LaxBoundedSemaphore(2)
-
- >>> x.acquire(printf, 'HELLO 1')
- HELLO 1
-
- >>> x.acquire(printf, 'HELLO 2')
- HELLO 2
-
- >>> x.acquire(printf, 'HELLO 3')
- >>> x._waiters # private, do not access directly
- [print, ('HELLO 3', )]
-
- >>> x.release()
- HELLO 3
-
- """
-
- def __init__(self, value):
- self.initial_value = self.value = value
- self._waiting = deque()
- self._add_waiter = self._waiting.append
- self._pop_waiter = self._waiting.popleft
-
- def acquire(self, callback, *partial_args):
- """Acquire semaphore, applying ``callback`` if
- the resource is available.
-
- :param callback: The callback to apply.
- :param \*partial_args: partial arguments to callback.
-
- """
- value = self.value
- if value <= 0:
- self._add_waiter((callback, partial_args))
- return False
- else:
- self.value = max(value - 1, 0)
- callback(*partial_args)
- return True
-
- def release(self):
- """Release semaphore.
-
- If there are any waiters this will apply the first waiter
- that is waiting for the resource (FIFO order).
-
- """
- try:
- waiter, args = self._pop_waiter()
- except IndexError:
- self.value = min(self.value + 1, self.initial_value)
- else:
- waiter(*args)
-
- def grow(self, n=1):
- """Change the size of the semaphore to accept more users."""
- self.initial_value += n
- self.value += n
- [self.release() for _ in range(n)]
-
- def shrink(self, n=1):
- """Change the size of the semaphore to accept less users."""
- self.initial_value = max(self.initial_value - n, 0)
- self.value = max(self.value - n, 0)
-
- def clear(self):
- """Reset the semaphore, which also wipes out any waiting callbacks."""
- self._waiting.clear()
- self.value = self.initial_value
-
- def __repr__(self):
- return '<{0} at {1:#x} value:{2} waiting:{3}>'.format(
- self.__class__.__name__, id(self), self.value, len(self._waiting),
- )
-
-
- class DummyLock(object):
- """Pretending to be a lock."""
-
- def __enter__(self):
- return self
-
- def __exit__(self, *exc_info):
- pass
|