@@ -203,18 +203,7 @@ def setup_and_check(self):
203203
204204 self .plotsDirectory = build_config_full_path (self .config , 'output' ,
205205 'plotsSubdirectory' )
206- namelistFileName = build_config_full_path (
207- self .config , 'input' ,
208- '{}NamelistFileName' .format (self .componentName ))
209- self .namelist = NameList (namelistFileName )
210-
211- streamsFileName = build_config_full_path (
212- self .config , 'input' ,
213- '{}StreamsFileName' .format (self .componentName ))
214- self .runStreams = StreamsFile (streamsFileName ,
215- streamsdir = self .runDirectory )
216- self .historyStreams = StreamsFile (streamsFileName ,
217- streamsdir = self .historyDirectory )
206+ self ._load_namelists_and_streams ()
218207
219208 self .calendar = self .namelist .get ('config_calendar_type' )
220209
@@ -282,6 +271,19 @@ def add_subtask(self, subtask):
282271 if subtask not in self .subtasks :
283272 self .subtasks .append (subtask )
284273
274+ def start (self ):
275+ """
276+ Clear unpicklable attributes and then start the analysis task as a new
277+ process.
278+ """
279+ # Authors
280+ # -------
281+ # Xylar Asay-Davis
282+ # clear unpicklable attributes before running the task
283+ self ._clear_namelists_and_streams ()
284+
285+ super (AnalysisTask , self ).start ()
286+
285287 def run (self , writeLogFile = True ):
286288 """
287289 Sets up logging and then runs the analysis task.
@@ -320,6 +322,9 @@ def run(self, writeLogFile=True):
320322
321323 startTime = time .time ()
322324 try :
325+ # reload namelists and streams, since they cannot be pickled
326+ # as part of multiprocessing
327+ self ._load_namelists_and_streams ()
323328 self .run_task ()
324329 self ._runStatus .value = AnalysisTask .SUCCESS
325330 except (Exception , BaseException ) as e :
@@ -525,6 +530,71 @@ def get_mesh_filename(self):
525530
526531 return meshFilename
527532
533+ def __getstate__ (self ):
534+ """
535+ Customize pickling to exclude unpicklable and unnecessary attributes.
536+ This method is called during multiprocessing when the task is
537+ serialized to be sent to a child process. We exclude task dependencies
538+ and process internals that don't need to be transferred, such as logger
539+ objects, process internals, and weakref-bearing attributes.
540+
541+ Returns
542+ -------
543+ state : dict
544+ The object state with unpicklable and unnecessary attributes
545+ removed.
546+ """
547+ state = self .__dict__ .copy ()
548+
549+ # Clear out attributes that should not be pickled
550+ state ['namelist' ] = None
551+ state ['runStreams' ] = None
552+ state ['historyStreams' ] = None
553+ state ['runAfterTasks' ] = []
554+ state ['subtasks' ] = []
555+ # Drop process internals and logger that can't/shouldn't be pickled
556+ for key in ['_popen' , 'logger' , '_stackTrace' ]:
557+ state .pop (key , None )
558+
559+ # Drop weakref-bearing Finalize, etc., by not pickling _popen at all
560+ # _runStatus is a multiprocessing.Value; depending on your logic,
561+ # you may also want to skip it and let child initialize its own.
562+
563+ return state
564+
565+ def _load_namelists_and_streams (self ):
566+ """
567+ Load namelist and streams attributes.
568+ """
569+ # Authors
570+ # -------
571+ # Xylar Asay-Davis
572+
573+ namelistFileName = build_config_full_path (
574+ self .config , 'input' ,
575+ '{}NamelistFileName' .format (self .componentName ))
576+ self .namelist = NameList (namelistFileName )
577+
578+ streamsFileName = build_config_full_path (
579+ self .config , 'input' ,
580+ '{}StreamsFileName' .format (self .componentName ))
581+ self .runStreams = StreamsFile (streamsFileName ,
582+ streamsdir = self .runDirectory )
583+ self .historyStreams = StreamsFile (streamsFileName ,
584+ streamsdir = self .historyDirectory )
585+
586+ def _clear_namelists_and_streams (self ):
587+ """
588+ Clear namelist and streams attributes that cannot be pickled for
589+ multiprocessing.
590+ """
591+ # Authors
592+ # -------
593+ # Xylar Asay-Davis
594+
595+ self .namelist = None
596+ self .runStreams = None
597+ self .historyStreams = None
528598# }}}
529599
530600
0 commit comments