class_docstr: 定制给 :class:`~fastNLP.core.dataloaders.MixDataLoader` 的 ``BatchSampler``，其功能是将传入的 ``datasets`` 
  字典混合采样组成一个个 batch 返回。
class_docstr_tok: ["\u5b9a\u5236\u7ed9",":","class",":","`","~fastNLP.core.dataloaders.MixDataLoader","`","\u7684","``","BatchSampler","``","\uff0c\u5176\u529f\u80fd\u662f\u5c06\u4f20\u5165\u7684","``","datasets","``","\u5b57\u5178\u6df7\u5408\u91c7\u6837\u7ec4\u6210\u4e00\u4e2a\u4e2a","batch","\u8fd4\u56de\u3002"]
code: def __iter__(self) -> List[int]:
      # sampler 为 str， 此时为单机多卡或者单机，可以实现 rand 随机化
      if isinstance(self.sampler, str):
          if self.sampler == "seq":
              self.sampler = {}
              for name, per_ds in self.datasets.items():
                  if self.word_size >= 0 and self.rank >= 0:
                      self.sampler[name] = InnerSampler(
                          list(range(len(per_ds)))[
                              self.rank :: self.word_size
                          ]
                      )
                  else:
                      self.sampler[name] = InnerSampler(
                          list(range(len(per_ds)))
                      )
          elif self.sampler == "rand":
              self.sampler = {}
              for name, per_ds in self.datasets.items():
                  g = torch.Generator()
                  g.manual_seed(self.epoch)
                  indices = torch.randperm(
                      len(per_ds), generator=g
                  ).tolist()
                  if self.word_size >= 0 and self.rank >= 0:
                      self.sampler[name] = InnerSampler(
                          indices[self.rank :: self.word_size]
                      )
                  else:
                      self.sampler[name] = InnerSampler(indices)
  
          # 根据给定的ds_ratio计算真正需要处理数据集
          if isinstance(self.sampler, Dict):
              if self.ds_ratio is None:
                  sampler_lens = [
                      len(spl) for _, spl in self.sampler.items()
                  ]
  
              elif self.ds_ratio == "pad_to_most":
                  sampler_len = sum([1 for _ in self.sampler.keys()])
                  sampler_lens = [
                      max(len(spl) for _, spl in self.sampler.items())
                  ] * sampler_len
  
              elif self.ds_ratio == "truncate_to_least":
                  sampler_len = sum([1 for _ in self.sampler.keys()])
                  sampler_lens = [
                      min(len(spl) for _, spl in self.sampler.items())
                  ] * sampler_len
  
              elif isinstance(self.ds_ratio, Dict):
                  if not all(item >= 0 for item in self.ds_ratio):
                      raise ValueError(
                          "batch_size should be a positive integer value, "
                          "but got ds_ratio={}".format(self.ds_ratio)
                      )
                  sampler_lens = [
                      int(len(spl) * self.ds_ratio[name])
                      for name, spl in self.sampler.items()
                  ]
              else:
                  raise ValueError(
                      f"{self.ds_ratio} must be pad_to_least or truncate_to_least or None or List"
                  )
              total_lens = sum(sampler_lens)
          else:
              raise ValueError("datasets must be dict or list")
          # 初始化参数
          sampler_index = [sampler_lens[0]]
          for idx in sampler_lens[1:]:
              temp = sampler_index[-1]
              sampler_index.append(temp + idx)
          self.num_samplers = sampler_index
          self.len_samplers = total_lens
      # 每个 batch 的数据, 总的数据量 total_index , 每个数据集的 samplers
      batch_idx, samplers = [], []
      # 如果单机则用所有数据，否则采用多卡
      if self.rank < 0 or self.word_size < 0:
          # 根据 sampler 长度判断是否使用 unsigned int 或者 unsigned long
          if self.len_samplers > 42e8:
              total_index = array.array(
                  "L", list(range(self.len_samplers))
              )
          else:
              total_index = array.array(
                  "I", list(range(self.len_samplers))
              )
      else:
          if (self.len_samplers // self.word_size) > 42e8:
              # 整分给每个卡的数据
              self.len_samplers = (
                  self.len_samplers - self.len_samplers % self.word_size
              )
              total_index = array.array(
                  "L",
                  list(range(self.len_samplers))[
                      self.rank :: self.word_size
                  ],
              )
          else:
              total_index = array.array(
                  "I",
                  list(range(self.len_samplers))[
                      self.rank :: self.word_size
                  ],
              )
  
      start_idx = 0
  
      # （特定数据集需要长度，特定数据集sampler, 特定数据集的基址， 特定sampler的下标）
      for idx, (name, spl) in enumerate(self.sampler.items()):
          end_idx = len(spl)
          samplers.append((iter(spl), name, start_idx))
          start_idx += end_idx
      # 根据sampler的类型取出每个数据集的sampler
      # sampler_base_index = [0] + [len(spl) for _, spl in self.sampler.items()][:-1]
      # samplers = [(iter(spl), name, sampler_base_index[idx])
      #             for idx, (name, spl) in enumerate(self.sampler.items())]
      # 生成随机数
      np.random.seed(self.epoch)
      np.random.shuffle(total_index)
      for idx in total_index:
          ds_index = np.searchsorted(
              self.num_samplers, idx, side="right"
          )
          spl, name, base_index = samplers[ds_index]
          try:
              batch_idx.append(next(spl) + base_index)
          except StopIteration:
              # 重新初始化一个新的sampler，因为不可能为空，故一定不会出现stopIteration
              spl = iter(self.sampler[name])
              batch_idx.append(next(spl) + base_index)
              samplers[ds_index] = (spl, name, base_index)
          if len(batch_idx) == self.batch_size:
              yield batch_idx
              batch_idx = []
  
      if len(batch_idx) > 0 and not self.drop_last:
          yield batch_idx
  
imports: import array
  import numpy
  from typing import Union, List, Iterable, Dict
  from fastNLP.envs.imports import _NEED_IMPORT_TORCH
label_desc: Use image node_id 2 for calling the DopedSampler obj's underlying member method code with example usage: obj.__iter__() without return types