Asynchronous Programming

34.1 std/asyncdispatch

Future[T], await, waitFor, asyncCheck (fire and forget, crashes on error), all, or, withTimeout, callSoon, runForever, poll.

Built on closure iterators and OS selectors (epoll/kqueue/IOCP).

import std/[asyncdispatch, httpclient]

proc fetch(url: string): Future[string] {.async.} =
  let client = newAsyncHttpClient()
  defer: client.close()
  result = await client.getContent(url)

proc main() {.async.} =
  let futs = @[fetch("https://nim-lang.org"), fetch("https://example.com")]
  let pages = await all(futs)
  for p in pages: echo p.len
  await sleepAsync(500)

waitFor main()

34.2 Async Networking

import std/[asyncnet, asyncdispatch]
proc handle(client: AsyncSocket) {.async.} =
  while true:
    let line = await client.recvLine()
    if line.len == 0: break
    await client.send("echo: " & line & "\r\n")
  client.close()

proc serve() {.async.} =
  let server = newAsyncSocket()
  server.setSockOpt(OptReuseAddr, true)
  server.bindAddr(Port(9000))
  server.listen()
  while true:
    let client = await server.accept()
    asyncCheck handle(client)

waitFor serve()

34.3 Chronos

chronos (Status): an alternative async framework with stricter exception tracking (async: (raises: [...])), cancellation, better performance, and a rich ecosystem (chronos/apps/http, presto REST, websock, json_rpc).

asyncdispatch and chronos are not interoperable. Pick one per project.

34.4 Async Best Practices

Never block the event loop (CPU work goes to threads).

Handle errors on every future (try/await/except). Use timeouts.

Mixing threads and async: run separate dispatchers per thread and communicate via channels or AsyncEvent.