@@ -111,6 +111,29 @@ def _bootstrap_worker(obj, method_name, original_DT, i, seed, args, kwargs):
111111 return result
112112
113113
114+ # Process-pool worker state for the parallel bootstrap fit. Set once per
115+ # worker process by the initializer so each task ships only the replicate
116+ # index — not the (slimmed) SEQuential object or the full analysis frame,
117+ # which previously crossed the process boundary once per task.
118+ _FIT_WORKER_OBJ = None
119+ _FIT_WORKER_DATA = None
120+ _FIT_WORKER_CALL = None
121+
122+
123+ def _fit_pool_init (obj , data_ref , method_name , seed , args , kwargs ):
124+ global _FIT_WORKER_OBJ , _FIT_WORKER_DATA , _FIT_WORKER_CALL
125+ _FIT_WORKER_OBJ = obj
126+ _FIT_WORKER_DATA = obj ._offloader .load_dataframe (data_ref )
127+ _FIT_WORKER_CALL = (method_name , seed , args , kwargs )
128+
129+
130+ def _fit_pool_task (i ):
131+ method_name , seed , args , kwargs = _FIT_WORKER_CALL
132+ return _bootstrap_worker (
133+ _FIT_WORKER_OBJ , method_name , _FIT_WORKER_DATA , i , seed , args , kwargs
134+ )
135+
136+
114137def bootstrap_loop (method ):
115138 @wraps (method )
116139 def wrapper (self , * args , ** kwargs ):
@@ -150,19 +173,13 @@ def wrapper(self, *args, **kwargs):
150173 self ._rng = None
151174 self .DT = None
152175
153- with ProcessPoolExecutor (max_workers = ncores ) as executor :
176+ with ProcessPoolExecutor (
177+ max_workers = ncores ,
178+ initializer = _fit_pool_init ,
179+ initargs = (self , original_DT_ref , method_name , seed , args , kwargs ),
180+ ) as executor :
154181 futures = {
155- executor .submit (
156- _bootstrap_worker ,
157- self ,
158- method_name ,
159- original_DT_ref ,
160- i ,
161- seed ,
162- args ,
163- kwargs ,
164- ): i
165- for i in range (nboot )
182+ executor .submit (_fit_pool_task , i ): i for i in range (nboot )
166183 }
167184 skipped = 0
168185 boot_sample_idx = []
0 commit comments