class_docstr: Args:
      detached_trainer_name_list: str list to get ray actor handles
      strategy:
      kl_coef: the coefficient of kl divergence loss
      sync_models_from_trainers: whether to sync models from trainers. If True, you must call sync_models_to_remote_makers() in trainers to sync models.
class_docstr_tok: ["Args",":","detached_trainer_name_list",":","str","list","to","get","ray","actor","handles","strategy",":","kl_coef",":","the","coefficient","of","kl","divergence","loss","sync_models_from_trainers",":","whether","to","sync","models","from","trainers",".","If","True",",","you","must","call","sync_models_to_remote_makers","(",")","in","trainers","to","sync","models","."]
docstr: Working loop of the experience maker.
  
  Args:
      dataloader_fn (Callable[[], Iterable]): A function that returns a dataloader.
      num_epochs (int, optional): Iterate the dataloader for number of epochs. Defaults to 1.
      num_steps (int, optional): Iterate the dataloader for number if steps. If this value > 0, num_epochs will be ignored. Defaults to 0.
docstr_tok: ["Working","loop","of","the","experience","maker",".","Args",":","dataloader_fn","(","Callable","[","[","]",",","Iterable","]",")",":","A","function","that","returns","a","dataloader",".","num_epochs","(","int",",","optional",")",":","Iterate","the","dataloader","for","number","of","epochs",".","Defaults","to","1.","num_steps","(","int",",","optional",")",":","Iterate","the","dataloader","for","number","if","steps",".","If","this","value",">","0",",","num_epochs","will","be","ignored",".","Defaults","to","0","."]
code: def workingloop(
      self,
      dataloader_fn: Callable[[], Iterable],
      num_epochs: int = 1,
      num_steps: int = 0,
  ):
      """Working loop of the experience maker.
  
      Args:
          dataloader_fn (Callable[[], Iterable]): A function that returns a dataloader.
          num_epochs (int, optional): Iterate the dataloader for number of epochs. Defaults to 1.
          num_steps (int, optional): Iterate the dataloader for number if steps. If this value > 0, num_epochs will be ignored. Defaults to 0.
      """
      self._get_ready()
      self._on_loop_start()
      dataloader = dataloader_fn()
      if num_steps > 0:
          # ignore num epochs
          it = iter(dataloader)
          for _ in tqdm(
              range(num_steps),
              desc="ExperienceMaker",
              disable=not is_rank_0(),
          ):
              try:
                  batch = next(it)
              except StopIteration:
                  it = iter(dataloader)
                  batch = next(it)
              self._inference_step(batch)
      else:
          with tqdm(
              total=num_epochs * len(dataloader),
              desc="ExperienceMaker",
              disable=not is_rank_0(),
          ) as pbar:
              for _ in range(num_epochs):
                  for batch in dataloader:
                      self._inference_step(batch)
                      pbar.update()
      self._on_loop_end()
  
imports: import os
  import time
  import tracemalloc
  from threading import Lock
  from typing import Any, Callable, Dict, Iterable, List, Tuple, Union
  import ray
  import torch
  from coati.experience_buffer.utils import split_experience_batch
  from coati.experience_maker import Experience, NaiveExperienceMaker
  from coati.models.base import Actor, Critic, RewardModel
  from coati.trainer.strategies import Strategy
  from torch import Tensor
  from tqdm import tqdm
  from .callbacks import ExperienceMakerPerformanceEvaluator, MakerCallback
  from .lora_constructor import LoRAConstructor
  from .utils import get_model_numel, get_rank, is_rank_0, set_dist_env, state_dict_to
label_desc: Use image node_id 8 for calling the ExperienceMakerHolder obj's underlying member method code with example usage: obj.workingloop(dataloader_fn, num_epochs, num_steps) without return types