class_docstr: Manage profile data for each run, each run may have multiple workers and spans.
  We should manage profile data of each (worker, span) unit.
  Besides, a special worker "all" is created to merge all profile data for distributed view.
class_docstr_tok: ["Manage","profile","data","for","each","run",",","each","run","may","have","multiple","workers","and","spans",".","We","should","manage","profile","data","of","each","(","worker",",","span",")","unit",".","Besides",",","a","special","worker","``","all","''","is","created","to","merge","all","profile","data","for","distributed","view","."]
code: def join(self):
      for thread in self.threads.values():
          thread.join()
      distributed_profiler_data = defaultdict(list)
      for worker_name, span_data in self.profiler_data.items():
          for span_idx, profiler_data in span_data.items():
              distributed_profiler_data[span_idx].append(profiler_data)
      for span_idx, profiler_datas in distributed_profiler_data.items():
          self.distributed_data[span_idx] = DistributedProfilerData(
              self.run, span_idx, profiler_datas
          )
  
file_path: VisualDL/visualdl/component/profiler/run_manager.py
imports: from collections import defaultdict
  from threading import Thread
  from .profiler_data import DistributedProfilerData
  from .profiler_data import ProfilerData
label_desc: Use image node_id 9 for calling the RunManager obj's underlying member method code with example usage: obj.join() without return types