class_docstr: A `RuntimeGroup` is the representation of logically related `Runtimes`.
  
  The group provides convenient methods for managing those related `Runtimes`.
  Most methods are wrappers around their counterparts in the `Runtime` class.
  Typical usage examples are exposing a port (i.e. a service such as a DB) in
  the `RuntimeGroup`, transfer files, or execute  a `RuntimeTask` on the contained
  `Runtimes`. Additionally, all concrete RuntimeCluster (e.g. HyperoptCluster)
  implementations rely on `RuntimeGroups` for example.
  
  Examples:
  Execute a `RuntimeTask` in a `RuntimeGroup`
  
  ```python
  # Create instances
  group = RuntimeGroup([Runtime('host-1'), Runtime('host-2')])
  # group = RuntimeGroup(hosts=['host-1', 'host-2'])
  my_task = RuntimeTask('group-demo').run_command('echo Hello Group!')
  
  # Execute a RuntimeTask in a single Runtime
  single_task = group.execute_task(my_task)
  print(single_task.execution_log[0])
  
  # Execute a RuntimeTask in the whole RuntimeGroup
  task_list = group.execute_task(my_task, broadcast=True)
  
  # Execute a RuntimeTask on a single Runtime contained in the RuntimeGroup
  task = group.execute_task(my_task)
  ```
  
  A DB is running on localhost on port `local_port` and the DB is only accessible
  from localhost. But you also want to access the service on the other `Runtimes` on port
  `runtime_port`. Then you can use this method to expose the service which is running on the
  local machine to the remote machines.
  
  ```python
  # Expose a port to all Runtimes contained in the Runtime. If a port list is given the next free port is
  # chosen and returned.
  group_port = group.expose_port_to_runtimes(local_port=60000, runtime_port=list(range(60000,60010)))
  print('Local port 60000 is now exposed to port ' + str(group_port) + ' in the RuntimeGroup!')
  ```
  
  A DB is running on a remote host on port `runtime_port` and the DB is only accessible from the remote
  machine itself. But you also want to access the service to other `Runtimes` in the group. Then you can use
  this method to expose the service which is running on one `Runtime` to the whole group.
  
  ```python
  # Expose a port from a Runtime to all other ones in the RuntimeGroup. If a port list is given the next
  # free port is chosen and returned.
  group_port = group.expose_port_from_runtime_to_group(host='host-1', runtime_port=60000,
                                                          group_port=list(range(60000,60010)))
  print('Port 60000 of `host-1` is now exposed to port ' + str(group_port) + ' in the RuntimeGroup!')
  ```
class_docstr_tok: ["A","`","RuntimeGroup","`","is","the","representation","of","logically","related","`","Runtimes","`",".","The","group","provides","convenient","methods","for","managing","those","related","`","Runtimes","`",".","Most","methods","are","wrappers","around","their","counterparts","in","the","`","Runtime","`","class",".","Typical","usage","examples","are","exposing","a","port","(","i.e",".","a","service","such","as","a","DB",")","in","the","`","RuntimeGroup","`",",","transfer","files",",","or","execute","a","`","RuntimeTask","`","on","the","contained","`","Runtimes","`",".","Additionally",",","all","concrete","RuntimeCluster","(","e.g",".","HyperoptCluster",")","implementations","rely","on","`","RuntimeGroups","`","for","example",".","Examples",":","Execute","a","`","RuntimeTask","`","in","a","`","RuntimeGroup","`","``","`","python","#","Create","instances","group","=","RuntimeGroup","(","[","Runtime","(","'host-1","'",")",",","Runtime","(","'host-2","'",")","]",")","#","group","=","RuntimeGroup","(","hosts=","[","'host-1","'",",","'host-2","'","]",")","my_task","=","RuntimeTask","(","'group-demo","'",")",".run_command","(","'echo","Hello","Group","!","'",")","#","Execute","a","RuntimeTask","in","a","single","Runtime","single_task","=","group.execute_task","(","my_task",")","print","(","single_task.execution_log","[","0","]",")","#","Execute","a","RuntimeTask","in","the","whole","RuntimeGroup","task_list","=","group.execute_task","(","my_task",",","broadcast=True",")","#","Execute","a","RuntimeTask","on","a","single","Runtime","contained","in","the","RuntimeGroup","task","=","group.execute_task","(","my_task",")","``","`","A","DB","is","running","on","localhost","on","port","`","local_port","`","and","the","DB","is","only","accessible","from","localhost",".","But","you","also","want","to","access","the","service","on","the","other","`","Runtimes","`","on","port","`","runtime_port","`",".","Then","you","can","use","this","method","to","expose","the","service","which","is","running","on","the","local","machine","to","the","remote","machines",".","``","`","python","#","Expose","a","port","to","all","Runtimes","contained","in","the","Runtime",".","If","a","port","list","is","given","the","next","free","port","is","#","chosen","and","returned",".","group_port","=","group.expose_port_to_runtimes","(","local_port=60000",",","runtime_port=list","(","range","(","60000,60010",")",")",")","print","(","'Local","port","60000","is","now","exposed","to","port","'","+","str","(","group_port",")","+","'","in","the","RuntimeGroup","!","'",")","``","`","A","DB","is","running","on","a","remote","host","on","port","`","runtime_port","`","and","the","DB","is","only","accessible","from","the","remote","machine","itself",".","But","you","also","want","to","access","the","service","to","other","`","Runtimes","`","in","the","group",".","Then","you","can","use","this","method","to","expose","the","service","which","is","running","on","one","`","Runtime","`","to","the","whole","group",".","``","`","python","#","Expose","a","port","from","a","Runtime","to","all","other","ones","in","the","RuntimeGroup",".","If","a","port","list","is","given","the","next","#","free","port","is","chosen","and","returned",".","group_port","=","group.expose_port_from_runtime_to_group","(","host='host-1","'",",","runtime_port=60000",",","group_port=list","(","range","(","60000,60010",")",")",")","print","(","'Port","60000","of","`","host-1","`","is","now","exposed","to","port","'","+","str","(","group_port",")","+","'","in","the","RuntimeGroup","!","'",")","``","`"]
docstr: Print information of contained `Runtimes`.
docstr_tok: ["Print","information","of","contained","`","Runtimes","`","."]
code: def print_runtime_info(self) -> None:
      """Print information of contained `Runtimes`."""
      # Ensure that all runtime info are read asynchronously before printing.
      # Otherwise each runtime will read its information synchronously.
      self.fill_runtime_info_buffers_async()
  
      for runtime in self.runtimes:
          runtime.print_info()
          print("\n")
  
imports: import atexit
  import logging
  import warnings
  from copy import deepcopy
  from multiprocessing import Pool, Process
  from typing import Dict, Generator, List, Optional, Union
  from storm import Storm
  from lazycluster import _utils
  from lazycluster.exceptions import InvalidRuntimeError, NoPortsLeftError, NoRuntimesDetectedError, PortInUseError
  from lazycluster.runtimes import Runtime, RuntimeTask
label_desc: Use image node_id 12 for calling the RuntimeGroup obj's underlying member method code with example usage: obj.print_runtime_info() without return types