class_docstr: Like ioloop.PeriodicCallback except the 'func' can be async and return
  a Future.
  
  Will wait for func to finish each time before we call it again. (Plain
  ioloop.PeriodicCallback can "pile up" invocations if they are taking too
  long.)
class_docstr_tok: ["Like","ioloop.PeriodicCallback","except","the","'func","'","can","be","async","and","return","a","Future",".","Will","wait","for","func","to","finish","each","time","before","we","call","it","again",".","(","Plain","ioloop.PeriodicCallback","can","``","pile","up","''","invocations","if","they","are","taking","too","long",".",")"]
code: def start(self) -> None:
      if self._started:
          raise RuntimeError("called start() twice on _AsyncPeriodic")
      self._started = True
  
      def invoke() -> InvokeResult:
          # important to start the sleep before starting callback so any initial
          # time spent in callback "counts against" the period.
          sleep_future = self.sleep()
          result = self._func()
  
          if result is None:
              return sleep_future
  
          callback_future = gen.convert_yielded(result)
          return gen.multi([sleep_future, callback_future])
  
      def on_done(future: gen.Future[None]) -> None:
          if not self._stopped:
              # mypy can't infer type of invoker for some reason
              self._loop.add_future(invoke(), on_done)  # type: ignore
          ex = future.exception()
          if ex is not None:
              log.error("Error thrown from periodic callback:")
              lines = format_exception(
                  ex.__class__, ex, ex.__traceback__
              )
              log.error("".join(lines))
  
      self._loop.add_future(self.sleep(), on_done)
  
imports: from __future__ import annotations
  import logging
  import sys
  import threading
  from collections import defaultdict
  from traceback import format_exception
  from typing import TYPE_CHECKING, Any, Awaitable, Callable, Union
  import tornado
  from tornado import gen
  from ..core.types import ID
label_desc: Use image node_id 3 for calling the _AsyncPeriodic obj's underlying member method code with example usage: obj.start() and returns: gen, sleep_future