@@ -46,6 +46,9 @@ def __init__(self) -> None:
4646 self ._queued : dict [str , SchedulableTask ] = {}
4747 self ._task_groups : dict [str , TaskGroupKey ] = {}
4848 self ._group_specs : dict [TaskGroupKey , TaskGroupSpec ] = {}
49+ self ._queued_by_group : Counter [TaskGroupKey ] = Counter ()
50+ self ._queued_resource_demand_by_group : dict [TaskGroupKey , Counter [SchedulerResourceKey ]] = defaultdict (Counter )
51+ self ._queued_peer_demand_by_resource : Counter [SchedulerResourceKey ] = Counter ()
4952 self ._group_finish : dict [TaskGroupKey , float ] = {}
5053 self ._heap : list [tuple [float , int , TaskGroupKey ]] = []
5154 self ._active_heap_keys : set [TaskGroupKey ] = set ()
@@ -69,6 +72,7 @@ def enqueue(self, items: Iterable[SchedulableTask]) -> tuple[str, ...]:
6972 queue .append (item )
7073 self ._queued [item .task_id ] = item
7174 self ._task_groups [item .task_id ] = item .group .key
75+ self ._increment_queue_accounting (item )
7276 self ._activate_group (item .group .key )
7377 accepted .append (item .task_id )
7478 if accepted :
@@ -77,10 +81,8 @@ def enqueue(self, items: Iterable[SchedulableTask]) -> tuple[str, ...]:
7781
7882 def discard (self , task_id : str ) -> None :
7983 """Remove a queued task lazily if it is no longer dispatchable."""
80- if task_id in self . _queued :
84+ if self . _remove_queued_item ( task_id ) is not None :
8185 self ._sequence_version += 1
82- self ._queued .pop (task_id , None )
83- self ._task_groups .pop (task_id , None )
8486
8587 def discard_where (self , predicate : Callable [[SchedulableTask ], bool ]) -> None :
8688 """Remove queued tasks matching a predicate."""
@@ -125,8 +127,7 @@ def commit(self, selection: QueueSelection) -> SchedulableTask | None:
125127 return None
126128
127129 queue .popleft ()
128- self ._queued .pop (item .task_id , None )
129- self ._task_groups .pop (item .task_id , None )
130+ self ._remove_queued_item (item .task_id )
130131 self ._active_heap_keys .discard (key )
131132 self ._active_heap_entries .pop (key , None )
132133 group = self ._group_specs [key ]
@@ -140,35 +141,34 @@ def commit(self, selection: QueueSelection) -> SchedulableTask | None:
140141 return item
141142
142143 def view (self ) -> QueueView :
143- queued_by_group : Counter [TaskGroupKey ] = Counter ()
144- demand_by_group : dict [TaskGroupKey , dict [SchedulerResourceKey , int ]] = defaultdict (lambda : defaultdict (int ))
145144 first_by_group : dict [TaskGroupKey , Mapping [SchedulerResourceKey , int ]] = {}
146145 first_tasks_by_group : dict [TaskGroupKey , SchedulableTask ] = {}
147146 first_group_specs : dict [TaskGroupKey , TaskGroupSpec ] = {}
148- demand_by_resource : Counter [SchedulerResourceKey ] = Counter ()
149-
150- for item in self ._queued .values ():
151- key = item .group .key
152- queued_by_group [key ] += 1
153- for resource , amount in item .resource_request .amounts .items ():
154- demand_by_group [key ][resource ] += amount
155- demand_by_resource [resource ] += amount
156147
157148 for key , queue in self ._queues .items ():
149+ if self ._queued_by_group .get (key , 0 ) <= 0 :
150+ continue
158151 first = self ._first_valid_item (key )
159- if first is not None :
160- first_by_group [key ] = dict (first .resource_request .amounts )
161- first_tasks_by_group [key ] = first
162- first_group_specs [key ] = first .group
152+ if first is None :
153+ continue
154+ first_by_group [key ] = dict (first .resource_request .amounts )
155+ first_tasks_by_group [key ] = first
156+ first_group_specs [key ] = first .group
163157
164158 return QueueView (
165159 queued_total = len (self ._queued ),
166- queued_by_group = dict (queued_by_group ),
167- queued_resource_demand_by_group = {key : dict (value ) for key , value in demand_by_group .items ()},
160+ queued_by_group = {key : count for key , count in self ._queued_by_group .items () if count > 0 },
161+ queued_resource_demand_by_group = {
162+ key : {resource : count for resource , count in value .items () if count > 0 }
163+ for key , value in self ._queued_resource_demand_by_group .items ()
164+ if self ._queued_by_group .get (key , 0 ) > 0
165+ },
168166 first_candidate_resources_by_group = first_by_group ,
169167 first_candidate_tasks_by_group = first_tasks_by_group ,
170168 first_candidate_group_specs_by_group = first_group_specs ,
171- queued_peer_demand_by_resource = dict (demand_by_resource ),
169+ queued_peer_demand_by_resource = {
170+ resource : count for resource , count in self ._queued_peer_demand_by_resource .items () if count > 0
171+ },
172172 )
173173
174174 def _activate_group (self , key : TaskGroupKey ) -> None :
@@ -183,13 +183,11 @@ def _activate_group(self, key: TaskGroupKey) -> None:
183183 self ._active_heap_entries [key ] = (finish , self ._sequence )
184184
185185 def _first_valid_item (self , key : TaskGroupKey ) -> SchedulableTask | None :
186+ self ._purge_queue_head (key )
186187 queue = self ._queues .get (key )
187- if queue is None :
188+ if not queue :
188189 return None
189- for item in queue :
190- if item .task_id in self ._queued and self ._task_groups .get (item .task_id ) == key :
191- return item
192- return None
190+ return queue [0 ]
193191
194192 def _purge_queue_head (self , key : TaskGroupKey ) -> None :
195193 queue = self ._queues .get (key )
@@ -200,3 +198,37 @@ def _purge_queue_head(self, key: TaskGroupKey) -> None:
200198 if item .task_id in self ._queued and self ._task_groups .get (item .task_id ) == key :
201199 break
202200 queue .popleft ()
201+
202+ def _increment_queue_accounting (self , item : SchedulableTask ) -> None :
203+ key = item .group .key
204+ self ._queued_by_group [key ] += 1
205+ for resource , amount in item .resource_request .amounts .items ():
206+ self ._queued_resource_demand_by_group [key ][resource ] += amount
207+ self ._queued_peer_demand_by_resource [resource ] += amount
208+
209+ def _remove_queued_item (self , task_id : str ) -> SchedulableTask | None :
210+ item = self ._queued .pop (task_id , None )
211+ key = self ._task_groups .pop (task_id , None )
212+ if item is None or key is None :
213+ return item
214+ self ._decrement_queue_accounting (item , key )
215+ return item
216+
217+ def _decrement_queue_accounting (self , item : SchedulableTask , key : TaskGroupKey ) -> None :
218+ self ._queued_by_group [key ] -= 1
219+ if self ._queued_by_group [key ] <= 0 :
220+ del self ._queued_by_group [key ]
221+
222+ group_demand = self ._queued_resource_demand_by_group .get (key )
223+ if group_demand is not None :
224+ for resource , amount in item .resource_request .amounts .items ():
225+ group_demand [resource ] -= amount
226+ if group_demand [resource ] <= 0 :
227+ del group_demand [resource ]
228+ if not group_demand :
229+ del self ._queued_resource_demand_by_group [key ]
230+
231+ for resource , amount in item .resource_request .amounts .items ():
232+ self ._queued_peer_demand_by_resource [resource ] -= amount
233+ if self ._queued_peer_demand_by_resource [resource ] <= 0 :
234+ del self ._queued_peer_demand_by_resource [resource ]
0 commit comments