title: Handling tasks that never terminate in python3 asyncio
body: <p>Sometimes async tasks have no meaningful termination condition - for instance, in the program below, the "rate_limiter" task generates a stream of tokens on a queue, at a fixed rate, forever.</p>
  
  <pre><code>import asyncio
  import sys
  
  @asyncio.coroutine
  def rate_limiter(queue, rate):
      """Push tokens to QUEUE at a rate of RATE per second."""
      delay = 1/rate
      while True:
          yield from asyncio.sleep(delay)
          yield from queue.put(None)
  
  @asyncio.coroutine
  def do_work(n, rate):
      for i in range(n):
          yield from rate.get()
          sys.stdout.write("job {}\n".format(i))
  
  def main():
      loop   = asyncio.get_event_loop()
      rate   = asyncio.Queue()
      rltask = loop.create_task(rate_limiter(rate, 10))
      wtask  = loop.create_task(do_work(20, rate))
      loop.run_until_complete(wtask)
  
  main()
  </code></pre>
  
  <p>This program works perfectly <em>except</em> that the asyncio library considers it a programming error to just throw away <code>rltask</code> when there's nothing left to rate-limit; you get a complaint like</p>
  
  <pre><code>...
  job 18
  job 19
  Task was destroyed but it is pending!
  task: &lt;Task pending coro=&lt;rate_limiter() running at rl.py:9&gt;
        wait_for=&lt;Future pending cb=[Task._wakeup()]&gt;&gt;
  </code></pre>
  
  <p>(whether or not in debug mode).</p>
  
  <p>I can kludge around this with, like, an Event that tells the <code>rate_limiter</code> coroutine to break out of its loop, but that feels like extra code to no real benefit.  How are you <em>supposed</em> to deal with this sort of situation when using asyncio?</p>
  
  <p><strong>EDIT:</strong> I was unclear: what I am looking for is something like the <code>daemon</code> flag on threads: something that makes it so I <em>don't have to wait for a particular task,</em> ideally expressed as an annotation on the task itself, or its coroutine.  I would also accept an answer that demonstrates that there is no such mechanism.  I'm already aware of workarounds.</p>