diff --git a/CHANGELOG.md b/CHANGELOG.md
index 291a6a613e11f096df942a52ded5c80886684cae..5681236cdbc29fc3ac119f4c054da40899a67c46 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,8 @@
 * fixed circular import
 * added __len__ to PeekableQueue
 * fixed CallableGroup, added new class
+* added enum to DictDeleter
+* added faster enumeration to PeekableQueue
 
 # v2.25.5
 
diff --git a/docs/coding/sequences.rst b/docs/coding/sequences.rst
index 777cd9ad5ac2fb75e715e31fc114174e33a76fb7..7ee25075aa7c73bfbcfc4ba35daf00c405b2bd71 100644
--- a/docs/coding/sequences.rst
+++ b/docs/coding/sequences.rst
@@ -312,5 +312,9 @@ ListDeleter
 DictDeleter
 -----------
 
+.. autoclass:: satella.coding.IterMode:
+    :members:
+
+
 .. autoclass:: satella.coding.DictDeleter
     :members:
diff --git a/satella/__init__.py b/satella/__init__.py
index abf44da4c2c18520c722effa9d727fcfcc463780..e9c30031ab69b3fbb5a14c73c509ee4a390abf9f 100644
--- a/satella/__init__.py
+++ b/satella/__init__.py
@@ -1 +1 @@
-__version__ = '2.25.6a7'
+__version__ = '2.25.6a8'
diff --git a/satella/coding/concurrent/callablegroup.py b/satella/coding/concurrent/callablegroup.py
index cf59aee7a38b939d4a0cc9d21887a5dc48769d81..ac79846da369925556c36c7575a6a9bf531d7116 100644
--- a/satella/coding/concurrent/callablegroup.py
+++ b/satella/coding/concurrent/callablegroup.py
@@ -4,7 +4,7 @@ import copy
 import time
 import typing as tp
 
-from satella.coding.deleters import DictDeleter
+from satella.coding.deleters import DictDeleter, IterMode
 from satella.coding.typing import T, NoArgCallable
 
 
@@ -33,16 +33,16 @@ class CancellableCallback:
     def __bool__(self) -> bool:
         return not self.cancelled
 
-    def __init__(self, callback_fun: tp.Callable, one_shotted=False):
+    def __init__(self, callback_fun: tp.Callable):
         self.callback_fun = callback_fun
         self.cancelled = False
-        self.one_shotted = one_shotted
+        self.one_shotted = False
 
     def __hash__(self):
         return hash(id(self))
 
     def __eq__(self, other: CancellableCallback) -> bool:
-        return id(self) == id(other) and self.one_shotted == other.one_shotted and self.cancelled == other.cancelled
+        return id(self) == id(other) and self.cancelled == other.cancelled
 
     def __call__(self, *args, **kwargs):
         if not self.cancelled:
@@ -55,7 +55,7 @@ class CancellableCallback:
         self.cancelled = True
 
 
-def _callable_to_cancellablecallback(callback: NoArgCallable[[T], None], one_shot=False) -> CancellableCallback:
+def _callable_to_cancellablecallback(callback: NoArgCallable[[T], None]) -> CancellableCallback:
     if isinstance(callback, NoArgCallable[[T], None]):
         return CancellableCallback(callback)
     elif isinstance(callback, CancellableCallback):
@@ -111,8 +111,7 @@ class CallableGroup(tp.Generic[T]):
     __slots__ = 'callables', 'gather', 'swallow_exceptions',
 
     def __init__(self, gather: bool = True, swallow_exceptions: bool = False):
-
-        self.callables = collections.OrderedDict()  # type: tp.Dict[tp.Callable, tuple[bool, int]]
+        self.callables = collections.OrderedDict()  # type: tp.Dict[tp.Callable, tuple[bool]]
         self.gather = gather  # type: bool
         self.swallow_exceptions = swallow_exceptions  # type: bool
 
@@ -130,12 +129,14 @@ class CallableGroup(tp.Generic[T]):
 
     def remove_cancelled(self) -> None:
         """
-        Remove it's entries that are CancelledCallbacks and that were cancelled
+        Remove it's entries that are CancelledCallbacks and that were cancelled and move one shots
         """
-        with DictDeleter(self.callables) as dd:
-            for callable_ in dd:
+        with DictDeleter(self.callables, iter_mode=IterMode.ITER_VALUES) as dd:
+            for callable_, oneshot in dd:
                 if isinstance(callable_, CancellableCallback) and not callable_:
                     dd.delete()
+                if oneshot:
+                    dd.delete()
 
     def add_many(self, callable_: tp.Sequence[tp.Union[NoArgCallable[T],
                  tp.Tuple[NoArgCallable[T], bool]]]) -> CancellableCallbackGroup:
@@ -154,8 +155,13 @@ class CallableGroup(tp.Generic[T]):
 
         cancellable_callbacks = []
         for clbl in callable_:
-            canc_callback = _callable_to_cancellablecallback(clbl)
-            self.add(canc_callback, one_shot=canc_callback.one_shotted)
+            if isinstance(clbl, tuple):
+                clbl_, one_shot = clbl
+                canc_callback = _callable_to_cancellablecallback(clbl_)
+            else:
+                one_shot = False
+            cancellable_callbacks.append(canc_callback)
+            self.add(canc_callback, one_shot=one_shot)
             return CancellableCallbackGroup(cancellable_callbacks)
 
     def add(self, callable_: tp.Union[CancellableCallback, NoArgCallable[T]],
@@ -180,10 +186,10 @@ class CallableGroup(tp.Generic[T]):
             Do not pass a CancellableCallback, you'll get your own
         """
         if not isinstance(callable_, CancellableCallback):
-            callable_ = CancellableCallback(callable_)
+            callable_ = _callable_to_cancellablecallback(callable_)
+            self.callables[callable_] = one_shot
         if callable_ in self.callables:
             return callable_
-        self.callables[callable_] = one_shot
         return callable_
 
     def __call__(self, *args, **kwargs) -> tp.Optional[tp.List[T]]:
diff --git a/satella/coding/concurrent/queue.py b/satella/coding/concurrent/queue.py
index fce6a064783cf0b38cee5287f0e5718f3806325a..264e1f4401e9b43db08eb3d6c118e82e95a2ace1 100644
--- a/satella/coding/concurrent/queue.py
+++ b/satella/coding/concurrent/queue.py
@@ -75,18 +75,21 @@ class PeekableQueue(tp.Generic[T]):
 
     @rethrow_as(WouldWaitMore, Empty)
     def __get(self, timeout, item_getter) -> T:
-        self.lock.acquire()
-        if len(self.queue):
-            # Fast path
-            try:
-                return item_getter(self.queue)
-            finally:
-                self.lock.release()
-        else:
-            if timeout is None:
-                return self.__get_timeout_none(item_getter)
+        try:
+            self.lock.acquire()
+            if len(self.queue):
+                # Fast path
+                try:
+                    return item_getter(self.queue)
+                finally:
+                    self.lock.release()
             else:
-                return self.__get_timeout(item_getter, timeout)
+                if timeout is None:
+                    return self.__get_timeout_none(item_getter)
+                else:
+                    return self.__get_timeout(item_getter, timeout)
+        finally:
+            self.items_count -= 1
 
     def get(self, timeout: tp.Optional[float] = None) -> T:
         """
@@ -97,7 +100,10 @@ class PeekableQueue(tp.Generic[T]):
         :return: the item
         :raise Empty: queue was empty
         """
-        return self.__get(timeout, lambda queue: queue.popleft())
+        try:
+            return self.__get(timeout, lambda queue: queue.popleft())
+        finally:
+            self.items_count -= 1
 
     def peek(self, timeout: tp.Optional[float] = None) -> T:
         """
diff --git a/satella/coding/deleters.py b/satella/coding/deleters.py
index 0fb14279d5f0fd7602ff584eb7fffb8feb74f9a3..a5a27af3ffd25f88ebcf8d374bf7fd2bbac8d852 100644
--- a/satella/coding/deleters.py
+++ b/satella/coding/deleters.py
@@ -1,12 +1,14 @@
 import collections
 import copy
+import enum
 import typing as tp
 
 from satella.coding.typing import T
 
-ITER_KEYS = 0
-ITER_VALUES = 1
-ITER_ITEMS = 2
+class IterMode(enum.IntEnum):
+    ITER_KEYS = 0
+    ITER_VALUES = 1
+    ITER_ITEMS = 2
 
 
 class DictDeleter:
@@ -37,9 +39,9 @@ class DictDeleter:
     __slots__ = ('dict_to_process', 'current_iterator', 'keys_to_delete', 'iter_mode',
                  'current_key')
 
-    def __init__(self, dict_to_process: collections.abc.MutableMapping):
+    def __init__(self, dict_to_process: collections.abc.MutableMapping, iter_mode: IterMode.ITER_KEYS):
         self.dict_to_process = dict_to_process
-        self.iter_mode = ITER_KEYS
+        self.iter_mode = iter_mode
 
     def __enter__(self):
         self.keys_to_delete = set()
@@ -52,23 +54,23 @@ class DictDeleter:
     def __next__(self):
         key, value = next(self.current_iterator)  # raises StopIteration
         self.current_key = key
-        if self.iter_mode == ITER_ITEMS:
+        if self.iter_mode == IterMode.ITER_ITEMS:
             return key, value
-        elif self.iter_mode == ITER_VALUES:
+        elif self.iter_mode == IterMode.ITER_VALUES:
             return value
-        elif self.iter_mode == ITER_KEYS:
+        elif self.iter_mode == IterMode.ITER_KEYS:
             return key
 
     def items(self) -> 'DictDeleter':
-        self.iter_mode = ITER_ITEMS
+        self.iter_mode = IterMode.ITER_ITEMS
         return self
 
     def keys(self) -> 'DictDeleter':
-        self.iter_mode = ITER_KEYS
+        self.iter_mode = IterMode.ITER_KEYS
         return self
 
     def values(self) -> 'DictDeleter':
-        self.iter_mode = ITER_VALUES
+        self.iter_mode = IterMode.ITER_VALUES
         return self
 
     def delete(self) -> None:
diff --git a/tests/test_coding/test_concurrent.py b/tests/test_coding/test_concurrent.py
index 957002bc7119912d9bd7692f6ac5a758f9a72724..a0c58a36d6c081e6c715a6a8f0f00135b01520a0 100644
--- a/tests/test_coding/test_concurrent.py
+++ b/tests/test_coding/test_concurrent.py
@@ -274,7 +274,7 @@ class TestConcurrent(unittest.TestCase):
         cbgroup.add(CancellableCallback(p, one_shotted=False))
         cbgroup()
         self.assertEqual(a[1],3)
-        self.assertEqual(a[3], 4)
+        self.assertEqual(a[3], 5)
         self.assertEqual(a[4], 7)
         cbgroup()
         self.assertEqual(a[4], 8)