docs: def async_thread(sol, args, node_attr, node_id, *a, **kw):
      """
      Execute `sol._evaluate_node` in an asynchronous thread.
  
      :param sol:
          Solution to be updated.
      :type sol: schedula.utils.sol.Solution
  
      :param args:
          Arguments to be passed to node calls.
      :type args: tuple
  
      :param node_attr:
          Dictionary of node attributes.
      :type node_attr: dict
  
      :param node_id:
          Data or function node id.
      :type node_id: str
  
      :param a:
          Extra args to invoke `sol._evaluate_node`.
      :type a: tuple
  
      :param kw:
          Extra kwargs to invoke `sol._evaluate_node`.
      :type kw: dict
  
      :return:
          Function result.
      :rtype: concurrent.futures.Future | AsyncList
      """
      executor = _get_executor(_executor_name(kw.get('executor', False), sol.dsp))
      if not executor:
          return sol._evaluate_node(args, node_attr, node_id, *a, **kw)
  
      futures = args
      if node_attr['type'] == 'data' and (
              node_attr['wait_inputs'] or 'function' in node_attr):
          futures = args[0].values()
      from concurrent.futures import Future
      futures = {v for v in futures if isinstance(v, Future)}
  
      def _submit():
          return executor.thread(
              _async_eval, sol, args, node_attr, node_id, *a, **kw
          )
  
      if futures:  # Chain results.
          result = Future()
  
          def _set_res(fut):
              try:
                  result.set_result(fut.result())
              except BaseException as ex:
                  result.set_exception(ex)
  
          def _submit_task(fut=None):
              futures.discard(fut)
              not futures and _submit().add_done_callback(_set_res)
  
          for f in list(futures):
              f.add_done_callback(_submit_task)
      else:
          result = _submit()
  
      timeout = node_attr.get('await_result', False)
      if timeout is not False:
          return _await_result(result, timeout, sol, node_id)
  
      n = len(node_attr.get('outputs', []))
      return AsyncList(future=result, n=n) if n > 1 else result