code: def fail_fast_imap(pool, call, items):
      
      result_queue = LightQueue(maxsize=len(items))
      spawned_threads = set()
  
      def handle_result(finished_thread):
          try:
              thread_result = finished_thread.wait()
              spawned_threads.remove(finished_thread)
              result_queue.put((thread_result, None))
          except Exception:
              spawned_threads.remove(finished_thread)
              result_queue.put((None, sys.exc_info()))
  
      for item in items:
          gt = pool.spawn(call, item)
          spawned_threads.add(gt)
          gt.link(handle_result)
  
      while spawned_threads:
          result, exc_info = result_queue.get()
          if exc_info is not None:
              # Kill all other ongoing threads
              for ongoing_thread in spawned_threads:
                  ongoing_thread.kill()
              # simply raising here (even raising a full exc_info) isn't
              # sufficient to preserve the original stack trace.
              # greenlet.throw() achieves this.
              eventlet.getcurrent().throw(*exc_info)
          yield result
docs: Run a function against each item in a given list, yielding each
      function result in turn, where the function call is handled in a
      :class:`~eventlet.greenthread.GreenThread` spawned by the provided pool.
  
      If any function raises an exception, all other ongoing threads are killed,
      and the exception is raised to the caller.
  
      This function is similar to :meth:`~eventlet.greenpool.GreenPool.imap`.
  
      :param pool: Pool to spawn function threads from
      :type pool: eventlet.greenpool.GreenPool
      :param call: Function call to make, expecting to receive an item from the
          given list