m2m模型翻译
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.

115 lines
4.3 KiB

6 months ago
  1. from __future__ import absolute_import, division
  2. import collections
  3. import io
  4. import threading
  5. import time
  6. from kafka.metrics.stats import Rate
  7. import kafka.errors as Errors
  8. class SimpleBufferPool(object):
  9. """A simple pool of BytesIO objects with a weak memory ceiling."""
  10. def __init__(self, memory, poolable_size, metrics=None, metric_group_prefix='producer-metrics'):
  11. """Create a new buffer pool.
  12. Arguments:
  13. memory (int): maximum memory that this buffer pool can allocate
  14. poolable_size (int): memory size per buffer to cache in the free
  15. list rather than deallocating
  16. """
  17. self._poolable_size = poolable_size
  18. self._lock = threading.RLock()
  19. buffers = int(memory / poolable_size) if poolable_size else 0
  20. self._free = collections.deque([io.BytesIO() for _ in range(buffers)])
  21. self._waiters = collections.deque()
  22. self.wait_time = None
  23. if metrics:
  24. self.wait_time = metrics.sensor('bufferpool-wait-time')
  25. self.wait_time.add(metrics.metric_name(
  26. 'bufferpool-wait-ratio', metric_group_prefix,
  27. 'The fraction of time an appender waits for space allocation.'),
  28. Rate())
  29. def allocate(self, size, max_time_to_block_ms):
  30. """
  31. Allocate a buffer of the given size. This method blocks if there is not
  32. enough memory and the buffer pool is configured with blocking mode.
  33. Arguments:
  34. size (int): The buffer size to allocate in bytes [ignored]
  35. max_time_to_block_ms (int): The maximum time in milliseconds to
  36. block for buffer memory to be available
  37. Returns:
  38. io.BytesIO
  39. """
  40. with self._lock:
  41. # check if we have a free buffer of the right size pooled
  42. if self._free:
  43. return self._free.popleft()
  44. elif self._poolable_size == 0:
  45. return io.BytesIO()
  46. else:
  47. # we are out of buffers and will have to block
  48. buf = None
  49. more_memory = threading.Condition(self._lock)
  50. self._waiters.append(more_memory)
  51. # loop over and over until we have a buffer or have reserved
  52. # enough memory to allocate one
  53. while buf is None:
  54. start_wait = time.time()
  55. more_memory.wait(max_time_to_block_ms / 1000.0)
  56. end_wait = time.time()
  57. if self.wait_time:
  58. self.wait_time.record(end_wait - start_wait)
  59. if self._free:
  60. buf = self._free.popleft()
  61. else:
  62. self._waiters.remove(more_memory)
  63. raise Errors.KafkaTimeoutError(
  64. "Failed to allocate memory within the configured"
  65. " max blocking time")
  66. # remove the condition for this thread to let the next thread
  67. # in line start getting memory
  68. removed = self._waiters.popleft()
  69. assert removed is more_memory, 'Wrong condition'
  70. # signal any additional waiters if there is more memory left
  71. # over for them
  72. if self._free and self._waiters:
  73. self._waiters[0].notify()
  74. # unlock and return the buffer
  75. return buf
  76. def deallocate(self, buf):
  77. """
  78. Return buffers to the pool. If they are of the poolable size add them
  79. to the free list, otherwise just mark the memory as free.
  80. Arguments:
  81. buffer_ (io.BytesIO): The buffer to return
  82. """
  83. with self._lock:
  84. # BytesIO.truncate here makes the pool somewhat pointless
  85. # but we stick with the BufferPool API until migrating to
  86. # bytesarray / memoryview. The buffer we return must not
  87. # expose any prior data on read().
  88. buf.truncate(0)
  89. self._free.append(buf)
  90. if self._waiters:
  91. self._waiters[0].notify()
  92. def queued(self):
  93. """The number of threads blocked waiting on memory."""
  94. with self._lock:
  95. return len(self._waiters)