class_docstr: Abstract class for implementing the strategy for launching worker instances within a RuntimeGroup.
  
  In order to implement a new concrete `WorkerLauncher` subclass you need to implement the start method. Please
  consider the comments of the start method because some internal variables need to be set in the concrete
  implementation.
  
  Moreover, the `setup_worker_ssh_tunnels()` method can be used to setup ssh tunnels so that all entities can talk to
  each other.
class_docstr_tok: ["Abstract","class","for","implementing","the","strategy","for","launching","worker","instances","within","a","RuntimeGroup",".","In","order","to","implement","a","new","concrete","`","WorkerLauncher","`","subclass","you","need","to","implement","the","start","method",".","Please","consider","the","comments","of","the","start","method","because","some","internal","variables","need","to","be","set","in","the","concrete","implementation",".","Moreover",",","the","`","setup_worker_ssh_tunnels","(",")","`","method","can","be","used","to","setup","ssh","tunnels","so","that","all","entities","can","talk","to","each","other","."]
docstr: Launches the worker instances in the `RuntimeGroup`.
  
  Args:
      worker_count: The number of worker instances to be started in the group.
      master_port:  The port of the master instance.
      ports: The ports to be used for starting the workers. Only ports from the list will be chosen that are
             actually free.
      debug: If `True`, stdout/stderr from the runtime will be printed to stdout of localhost. If, `False` then
             the stdout/stderr will be added to python logger with level debug after each task step. Defaults to
             `False`.
  
  Returns:
      List[int]: The updated port list after starting the workers, i.e. the used ones were removed.
  
  Raises:
      NoPortsLeftError: If there are not enough free ports for starting all workers.
docstr_tok: ["Launches","the","worker","instances","in","the","`","RuntimeGroup","`",".","Args",":","worker_count",":","The","number","of","worker","instances","to","be","started","in","the","group",".","master_port",":","The","port","of","the","master","instance",".","ports",":","The","ports","to","be","used","for","starting","the","workers",".","Only","ports","from","the","list","will","be","chosen","that","are","actually","free",".","debug",":","If","`","True","`",",","stdout\/stderr","from","the","runtime","will","be","printed","to","stdout","of","localhost",".","If",",","`","False","`","then","the","stdout\/stderr","will","be","added","to","python","logger","with","level","debug","after","each","task","step",".","Defaults","to","`","False","`",".","Returns",":","List","[","int","]",":","The","updated","port","list","after","starting","the","workers",",","i.e",".","the","used","ones","were","removed",".","Raises",":","NoPortsLeftError",":","If","there","are","not","enough","free","ports","for","starting","all","workers","."]
code: def start(
      self,
      worker_count: int,
      master_port: int,
      ports: List[int],
      debug: bool = False,
  ) -> List[int]:
      """Launches the worker instances in the `RuntimeGroup`.
  
      Args:
          worker_count: The number of worker instances to be started in the group.
          master_port:  The port of the master instance.
          ports: The ports to be used for starting the workers. Only ports from the list will be chosen that are
                 actually free.
          debug: If `True`, stdout/stderr from the runtime will be printed to stdout of localhost. If, `False` then
                 the stdout/stderr will be added to python logger with level debug after each task step. Defaults to
                 `False`.
  
      Returns:
          List[int]: The updated port list after starting the workers, i.e. the used ones were removed.
  
      Raises:
          NoPortsLeftError: If there are not enough free ports for starting all workers.
      """
  
      # 1. The actual values for the following instance attributes need to be set within the concrete implementations:
      # - self._ports_per_host
  
      # 2. Raise `NoPortsLeftError` if there were not sufficient free ports in the list
  
      raise NotImplementedError
  
imports: import atexit
  import logging
  from subprocess import Popen
  from typing import Dict, List, Optional, Union
  from lazycluster.exceptions import LazyclusterError
  from lazycluster.runtime_mgmt import RuntimeGroup
label_desc: Use image node_id 4 for calling the WorkerLauncher obj's underlying member method code with example usage: obj.start(worker_count, master_port, ports, debug) without return types