title: Converting small functions to coroutines
body: <p>I feel like there is a gap in my understanding of async IO: <strong>is there a benefit to wrapping small functions into coroutines, within the scope of larger coroutines?</strong>  Is there a benefit to this in signaling the event loop correctly?  Does the extent of this benefit depend on whether the wrapped function is IO or CPU-bound?</p>
  
  <p>Example: I have a coroutine, <code>download()</code>, which:</p>
  
  <ol>
  <li>Downloads JSON-serialized bytes from an HTTP endpoint via <code>aiohttp</code>.</li>
  <li>Compresses those bytes via <a href="https://docs.python.org/3/library/bz2.html#one-shot-de-compression" rel="nofollow noreferrer"><code>bz2.compress()</code></a> - which is <strong>not in itself awaitable</strong></li>
  <li>Writes the compressed bytes to S3 via <a href="https://aioboto3.readthedocs.io/en/latest/installation.html" rel="nofollow noreferrer"><code>aioboto3</code></a></li>
  </ol>
  
  <p>So parts 1 &amp; 3 use predefined coroutines from those libraries; part 2 does not, by default.</p>
  
  <p>Dumbed-down example:</p>
  
  <pre><code>import bz2
  import io
  import aiohttp
  import aioboto3
  
  async def download(endpoint, bucket_name, key):
      async with aiohttp.ClientSession() as session:
          async with session.request("GET", endpoint, raise_for_status=True) as resp:
              raw = await resp.read()  # payload (bytes)
              # Yikes - isn't it bad to throw a synchronous call into the middle
              # of a coroutine?
              comp = bz2.compress(raw)
              async with (
                  aioboto3.session.Session()
                  .resource('s3')
                  .Bucket(bucket_name)
              ) as bucket:
                  await bucket.upload_fileobj(io.BytesIO(comp), key)
  </code></pre>
  
  <p>As hinted by the comment above, my understanding has always been that throwing a synchronous function like <code>bz2.compress()</code> into a coroutine can mess with it.  (Even if <code>bz2.compress()</code> is probably more IO-bound than CPU-bound.)</p>
  
  <p>So, is there generally any benefit to this type of boilerplate?</p>
  
  <pre><code>async def compress(*args, **kwargs):
      return bz2.compress(*args, **kwargs)
  </code></pre>
  
  <p>(And now <code>comp = await compress(raw)</code> within <code>download()</code>.)</p>
  
  <p>Wa-la, this is now an awaitable coroutine, because a sole <code>return</code> is valid in a native coroutine.  Is there a case to be made for using this?</p>
  
  <p>Per <a href="https://stackoverflow.com/a/55438300/7954504">this answer</a>, I've heard justification for randomly throwing in <code>asyncio.sleep(0)</code> in a similar manner - just to single back up to the event loop that the calling coroutine wants a break.  Is this right?</p>