title: asyncio: speculatively await multiple futures
body: <h3>TL;DR</h3>
  <p>How can I await any future from a collection of futures, optionally notifying other futures &quot;they are no longer needed&quot;?</p>
  <hr />
  <p>Here's why I need this.  I want to create a special kind of future / task that does timekeeping and may be used with other futures / tasks to cancel them if they cumulatively exceed some timeout (or are forced to stop after interacting with this timekeeping task).  If you are familiar with Go, it has a similar concept called <code>Context</code>.</p>
  <p>To make this even more concrete, imagine this.  You have a typical HTTP client.  It needs to perform several possibly forever blocking operations in succession in order to request a page from URL.  For example, these operations could be:</p>
  <ol>
  <li>Allocate a socket.</li>
  <li>Connect to server.</li>
  <li>Retrieve page in several chunks.</li>
  <li>Close connection.</li>
  <li>Deallocate socket.</li>
  </ol>
  <p>Suppose you allow for the entire operation to take a minute.  But you also know that allocating a socket should not take more than a millisecond, connecting may take up to a minute as well, same for retrieving chunks.  Disconnection and resource deallocation should take milliseconds.</p>
  <p>Suppose now you are made to wait full timeout on each bullet point--well, you've exceeded your quota more than twice.  So, you need to pass calculated delta from each call to its successor.  Also, suppose you couldn't deallocate the socket--well, no big deal, the application may recover from this error, so you also need to distinguish between kinds of timeouts.  I imagine this could be written like so (in some imaginary version of Python):</p>
  <pre><code>async def http_request(context, url):
      socket = await min(allocate_socket(), context.timeout, socket_timeout)
      await min(socket.connect(), context.timeout, connect_timeout)
      async for chunk in min(socket.receive(), context.timeout, chunk_timeout):
          print(chunk)
      await min(socket.close(), context.timeout, close_timeout)
  </code></pre>