@@ -859,21 +859,20 @@ static void executor_stop(void) {
859859/**
860860 * Main function for a multi-executor thread.
861861 * Each executor has its own queue and processes requests independently.
862+ *
863+ * GIL handling: Acquire GIL only when processing work, not while idle.
864+ * This prevents idle executors from competing with dirty schedulers
865+ * running actual Python work via the context-based API.
862866 */
863867static void * multi_executor_thread_main (void * arg ) {
864868 executor_t * exec = (executor_t * )arg ;
865869
866- /* Acquire GIL for this thread */
867- PyGILState_STATE gstate = PyGILState_Ensure ();
868-
869870 exec -> running = true;
870871
871872 while (!exec -> shutdown ) {
872873 py_request_t * req = NULL ;
873874
874- /* Release GIL while waiting for work */
875- Py_BEGIN_ALLOW_THREADS
876-
875+ /* Wait for work - NO GIL held while idle */
877876 pthread_mutex_lock (& exec -> mutex );
878877 while (exec -> queue_head == NULL && !exec -> shutdown ) {
879878 pthread_cond_wait (& exec -> cond , & exec -> mutex );
@@ -890,8 +889,6 @@ static void *multi_executor_thread_main(void *arg) {
890889 }
891890 pthread_mutex_unlock (& exec -> mutex );
892891
893- Py_END_ALLOW_THREADS
894-
895892 if (req != NULL ) {
896893 if (req -> type == PY_REQ_SHUTDOWN ) {
897894 pthread_mutex_lock (& req -> mutex );
@@ -900,10 +897,16 @@ static void *multi_executor_thread_main(void *arg) {
900897 pthread_mutex_unlock (& req -> mutex );
901898 break ;
902899 } else {
903- /* Process the request with GIL held */
900+ /* Acquire GIL only for actual work */
901+ PyGILState_STATE gstate = PyGILState_Ensure ();
902+
903+ /* Process the request */
904904 process_request (req );
905905
906- /* Signal completion */
906+ /* Release GIL immediately after processing */
907+ PyGILState_Release (gstate );
908+
909+ /* Signal completion (outside GIL) */
907910 pthread_mutex_lock (& req -> mutex );
908911 req -> completed = true;
909912 pthread_cond_signal (& req -> cond );
@@ -913,7 +916,6 @@ static void *multi_executor_thread_main(void *arg) {
913916 }
914917
915918 exec -> running = false;
916- PyGILState_Release (gstate );
917919
918920 return NULL ;
919921}
@@ -953,8 +955,8 @@ static int multi_executor_start(int num_executors) {
953955 return 0 ;
954956 }
955957
956- if (num_executors <= 0 ) {
957- num_executors = 4 ;
958+ if (num_executors < MIN_EXECUTORS ) {
959+ num_executors = MIN_EXECUTORS ;
958960 }
959961 if (num_executors > MAX_EXECUTORS ) {
960962 num_executors = MAX_EXECUTORS ;
0 commit comments