code: def start_workers(mode, urls, num_workers, inject_failure, s3config):
      # We start the minimum of len(urls) or num_workers to avoid starting
      # workers that will definitely do nothing
      num_workers = min(num_workers, len(urls))
      queue = Queue(len(urls) + num_workers)
      procs = {}
      random.seed()
  
      sz_results = []
      # 1. push sources and destinations to the queue
      # We only push if we don't inject a failure; otherwise, we already set the sz_results
      # appropriately with the result of the injected failure.
      for idx, elt in enumerate(urls):
          if random.randint(0, 99) < inject_failure:
              sz_results.append(-ERROR_TRANSIENT)
          else:
              sz_results.append(None)
              queue.put((elt, idx))
  
      # 2. push end-of-queue markers
      for i in range(num_workers):
          queue.put((None, None))
  
      # 3. start processes
      with TempDir() as output_dir:
          for i in range(num_workers):
              file_path = os.path.join(output_dir, str(i))
              p = Process(
                  target=worker,
                  args=(file_path, queue, mode, s3config),
              )
              p.start()
              procs[p] = file_path
  
          # 4. wait for the processes to finish; we continuously update procs
          # to remove all processes that have finished already
          while procs:
              new_procs = {}
              for proc, out_path in procs.items():
                  proc.join(timeout=1)
                  if proc.exitcode is not None:
                      if proc.exitcode != 0:
                          msg = (
                              "Worker process failed (exit code %d)"
                              % proc.exitcode
                          )
                          exit(msg, proc.exitcode)
                      # Read the output file if all went well
                      with open(out_path, "r") as out_file:
                          for line in out_file:
                              line_split = line.split(" ")
                              sz_results[int(line_split[0])] = int(
                                  line_split[1]
                              )
                  else:
                      # Put this process back in the processes to check
                      new_procs[proc] = out_path
              procs = new_procs
      return sz_results
  
imports: from __future__ import print_function
  import json
  import time
  import math
  import random
  import re
  import sys
  import os
  import traceback
  from collections import namedtuple
  from functools import partial, wraps
  from hashlib import sha1
  from tempfile import NamedTemporaryFile
  from multiprocessing import Process, Queue
  from itertools import starmap, chain, islice
  from boto3.s3.transfer import TransferConfig
  from metaflow._vendor import click
  from metaflow.util import TempDir, url_quote, url_unquote
  from metaflow.multicore_utils import parallel_map
  from metaflow.plugins.datatools.s3.s3util import aws_retry, read_in_chunks, get_timestamp, TRANSIENT_RETRY_LINE_CONTENT, TRANSIENT_RETRY_START_LINE
  import metaflow.tracing
label_desc: Use image node_id 4 for calling a global function with example usage: start_workers(mode, urls, num_workers, inject_failure, s3config) and returns: sz_results