title: Is python asyncio call_soon_threadsafe really thread-safe?
body: <p>I have saw some code that use <code>asyncio</code> as a asynchronous task queue. Maybe like following</p>
  
  <pre><code>async def _send_email(address):
      pass
  
  def send_email(address):
      task = asyncio.tasks.ensure_future(_send_email(address))
      task.add_done_callback(callback)
  
  def init_worker(loop):
      asyncio.set_event_loop(loop)
      loop.run_forever()
  
  @app.route("/notify")
  def do_jobs():
      # some code
      loop.call_soon_threadsafe(send_email, address)
  
  loop = asyncio.new_event_loop()
  worker = threading.Thread(target=init_worker, args=(loop,))
  worker.setDaemon(True)
  worker.start()
  
  app.run()
  </code></pre>
  
  <p>I read the implementation of <code>call_soon_threadsafe</code>. It will append the task to <code>loop._ready</code>, the code <a href="https://github.com/python/cpython/blob/master/Lib/asyncio/base_events.py#L573" rel="noreferrer">here</a>.</p>
  
  <pre><code>self._ready.append(handle)
  </code></pre>
  
  <p>But when the sub thread is executing <code>_run_once</code>, and pop the task from <code>loop._ready</code>, the code <a href="https://github.com/python/cpython/blob/master/Lib/asyncio/base_events.py#L1397" rel="noreferrer">here</a>.</p>
  
  <pre><code>handle = self._ready.popleft()
  </code></pre>
  
  <p>I'm not sure if the race condition exists or not. If it does not exist, under what circumstances should use the <code>queue.Queue</code>?</p>
  
  <p>Forgive my poor English.</p>