22import json
33import time
44import uuid
5- from concurrent .futures import ThreadPoolExecutor , as_completed
65from pathlib import Path
7- from threading import Lock
6+ from queue import Queue
7+ from threading import Lock , Thread
88
99from codeclash .agents .dummy_agent import Dummy
1010from codeclash .agents .utils import GameContext
@@ -211,16 +211,35 @@ def _evaluate_matrix_cell_parallel(
211211 result = stats .to_dict ()
212212 self .logger .debug (f"Result: { result } " )
213213
214- # Save the result immediately after computation
215214 with self ._save_lock :
216215 self .matrices [matrix_id ][str (i )][str (j )] = result
217216 self .output_file .write_text (json .dumps (self ._metadata , indent = 2 ))
218- self .logger .debug (f"Saved result for { player1_name } round { i } vs { player2_name } round { j } " )
219217
220218 return (i , j , result )
221219
220+ def _worker_thread (self , worker_id : int , task_queue : Queue ):
221+ """Worker thread that processes tasks using a specific game worker."""
222+ game_worker = self .game_pool [worker_id ]
223+ self .logger .debug (f"Worker { worker_id } started" )
224+
225+ while True :
226+ try :
227+ task = task_queue .get (timeout = 1 ) # Short timeout to allow clean exit
228+ except :
229+ # Queue is empty and no more tasks coming
230+ break
231+
232+ try :
233+ self ._evaluate_matrix_cell_parallel (game_worker , ** task )
234+ except Exception as e :
235+ self .logger .error (f"Worker { worker_id } failed on task { task } : { e } " )
236+ finally :
237+ task_queue .task_done ()
238+
239+ self .logger .debug (f"Worker { worker_id } stopped" )
240+
222241 def _evaluate_matrix (self , player1_name : str , player2_name : str ):
223- """Evaluate a matrix between two players using parallel execution ."""
242+ """Evaluate a matrix between two players using manual thread management ."""
224243 symmetric = player1_name == player2_name
225244 matrix_id = f"{ player1_name } _vs_{ player2_name } "
226245 self .logger .info (f"Evaluating { matrix_id } matrix: { player1_name } vs { player2_name } " )
@@ -230,9 +249,9 @@ def _evaluate_matrix(self, player1_name: str, player2_name: str):
230249 for i in range (self .rounds + 1 ):
231250 self .matrices [matrix_id ].setdefault (str (i ), {})
232251
233- # Collect all tasks to be executed
234- tasks = []
235- game_worker_index = 0
252+ # Create task queue and populate it directly
253+ task_queue = Queue ()
254+ task_count = 0
236255
237256 for i in range (self .rounds + 1 ):
238257 j_range = range (i ) if symmetric else range (self .rounds + 1 )
@@ -243,27 +262,30 @@ def _evaluate_matrix(self, player1_name: str, player2_name: str):
243262 continue
244263 except KeyError :
245264 pass
265+ task_queue .put (
266+ {"player1_name" : player1_name , "player2_name" : player2_name , "i" : i , "j" : j , "matrix_id" : matrix_id }
267+ )
268+ task_count += 1
246269
247- # Assign game worker in round-robin fashion
248- game_worker = self .game_pool [game_worker_index % len (self .game_pool )]
249- game_worker_index += 1
250-
251- tasks .append ((game_worker , player1_name , player2_name , i , j , matrix_id ))
252-
253- if not tasks :
270+ if task_count == 0 :
254271 self .logger .info (f"All matrix cells for { matrix_id } already completed" )
255272 return
256273
257- self .logger .info (f"Executing { len (tasks )} matrix cells in parallel with { self .max_workers } workers" )
258-
259- # Execute tasks in parallel
260- with ThreadPoolExecutor (max_workers = self .max_workers ) as executor :
261- # Submit all tasks
262- futures = [executor .submit (self ._evaluate_matrix_cell_parallel , * task ) for task in tasks ]
263-
264- # Wait for all tasks to complete
265- for future in as_completed (futures ):
266- future .result () # This will raise any exceptions that occurred
274+ self .logger .info (f"Executing { task_count } matrix cells using { self .max_workers } dedicated workers" )
275+
276+ # Start worker threads - each bound to a specific game worker
277+ self .logger .debug ("Starting worker threads" )
278+ workers = []
279+ for worker_id in range (self .max_workers ):
280+ worker = Thread (target = self ._worker_thread , args = (worker_id , task_queue ))
281+ worker .start ()
282+ workers .append (worker )
283+
284+ self .logger .debug ("Waiting for tasks to complete" )
285+ task_queue .join ()
286+ self .logger .debug ("Workers finished" )
287+ for worker in workers :
288+ worker .join ()
267289
268290 self .logger .info (f"Completed matrix evaluation for { matrix_id } " )
269291
0 commit comments