Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

semaphore.py 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. # -*- coding: utf-8 -*-
  2. """
  3. kombu.async.semaphore
  4. =====================
  5. Semaphores and concurrency primitives.
  6. """
  7. from __future__ import absolute_import
  8. from collections import deque
  9. __all__ = ['DummyLock', 'LaxBoundedSemaphore']
  10. class LaxBoundedSemaphore(object):
  11. """Asynchronous Bounded Semaphore.
  12. Lax means that the value will stay within the specified
  13. range even if released more times than it was acquired.
  14. Example:
  15. >>> from future import print_statement as printf
  16. # ^ ignore: just fooling stupid pyflakes
  17. >>> x = LaxBoundedSemaphore(2)
  18. >>> x.acquire(printf, 'HELLO 1')
  19. HELLO 1
  20. >>> x.acquire(printf, 'HELLO 2')
  21. HELLO 2
  22. >>> x.acquire(printf, 'HELLO 3')
  23. >>> x._waiters # private, do not access directly
  24. [print, ('HELLO 3', )]
  25. >>> x.release()
  26. HELLO 3
  27. """
  28. def __init__(self, value):
  29. self.initial_value = self.value = value
  30. self._waiting = deque()
  31. self._add_waiter = self._waiting.append
  32. self._pop_waiter = self._waiting.popleft
  33. def acquire(self, callback, *partial_args):
  34. """Acquire semaphore, applying ``callback`` if
  35. the resource is available.
  36. :param callback: The callback to apply.
  37. :param \*partial_args: partial arguments to callback.
  38. """
  39. value = self.value
  40. if value <= 0:
  41. self._add_waiter((callback, partial_args))
  42. return False
  43. else:
  44. self.value = max(value - 1, 0)
  45. callback(*partial_args)
  46. return True
  47. def release(self):
  48. """Release semaphore.
  49. If there are any waiters this will apply the first waiter
  50. that is waiting for the resource (FIFO order).
  51. """
  52. try:
  53. waiter, args = self._pop_waiter()
  54. except IndexError:
  55. self.value = min(self.value + 1, self.initial_value)
  56. else:
  57. waiter(*args)
  58. def grow(self, n=1):
  59. """Change the size of the semaphore to accept more users."""
  60. self.initial_value += n
  61. self.value += n
  62. [self.release() for _ in range(n)]
  63. def shrink(self, n=1):
  64. """Change the size of the semaphore to accept less users."""
  65. self.initial_value = max(self.initial_value - n, 0)
  66. self.value = max(self.value - n, 0)
  67. def clear(self):
  68. """Reset the semaphore, which also wipes out any waiting callbacks."""
  69. self._waiting.clear()
  70. self.value = self.initial_value
  71. def __repr__(self):
  72. return '<{0} at {1:#x} value:{2} waiting:{3}>'.format(
  73. self.__class__.__name__, id(self), self.value, len(self._waiting),
  74. )
  75. class DummyLock(object):
  76. """Pretending to be a lock."""
  77. def __enter__(self):
  78. return self
  79. def __exit__(self, *exc_info):
  80. pass