{"id":7906,"library":"aiochannel","title":"aiochannel","description":"aiochannel provides asyncio-compatible channels (closable queues) inspired by Go's concurrency model. It extends the functionality of `asyncio.Queue` by introducing a concept of a channel being 'closed and drained', guaranteeing that no further items can be added once closed. The library is active, with the current version being 1.3.0, and typically sees releases as needed for fixes or minor enhancements.","status":"active","version":"1.3.0","language":"en","source_language":"en","source_url":"https://github.com/tbug/aiochannel","tags":["asyncio","channel","queue","concurrency","golang-inspired","producer-consumer"],"install":[{"cmd":"pip install aiochannel","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"symbol":"Channel","correct":"from aiochannel import Channel"}],"quickstart":{"code":"import asyncio\nfrom aiochannel import Channel, ChannelClosed\n\nasync def producer(ch: Channel, num_items: int):\n    for i in range(num_items):\n        await ch.put(f\"item-{i}\")\n        print(f\"Produced item-{i}\")\n    ch.close()\n    print(\"Producer closed the channel\")\n\nasync def consumer(ch: Channel):\n    try:\n        async for item in ch:\n            print(f\"Consumed {item}\")\n    except ChannelClosed:\n        print(\"Consumer detected channel closed and drained.\")\n\nasync def main():\n    channel = Channel(10) # Create a channel with a buffer size of 10\n    await asyncio.gather(\n        producer(channel, 5),\n        consumer(channel)\n    )\n    # .join() waits until the channel is both closed and drained\n    await channel.join()\n    print(\"Channel is closed and drained, main exiting.\")\n\nif __name__ == \"__main__\":\n    asyncio.run(main())","lang":"python","description":"This quickstart demonstrates creating an `aiochannel.Channel`, with a producer coroutine putting items and a consumer coroutine retrieving them using an `async for` loop. The producer closes the channel, and the `channel.join()` call ensures the main program waits until all items are consumed and the channel is fully drained."},"warnings":[{"fix":"Design your application logic so that channel closure is an irreversible signal for no more data. If a channel needs to be 'reset', create a new `Channel` instance.","message":"Once an `aiochannel.Channel` is closed using `channel.close()`, it is a permanent state and cannot be reopened. Subsequent calls to `put()` will raise `ChannelClosed`.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always use `channel.join()` when you need to ensure all processing is complete and the channel is empty, after calling `channel.close()`. Do not rely on `channel.empty()` alone for this purpose if `close()` is involved.","message":"The `channel.join()` method in `aiochannel.Channel` behaves differently from `asyncio.Queue.join()`. `aiochannel.Channel.join()` waits until the channel is *both* closed (`.close()` has been called) and completely drained (all items have been retrieved). `asyncio.Queue.join()` only waits until the queue is empty.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Do not attempt to call `task_done()` on an `aiochannel.Channel` instance as it is not part of its API. Rely on `channel.close()` and `channel.join()` for managing completion.","message":"`aiochannel.Channel` does not implement `task_done()` or rely on it for its `join()` semantics, unlike `asyncio.Queue`. The completion signal for `aiochannel` is its `closed and drained` state.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Omit the `loop` argument when creating a `Channel` instance. `aiochannel` will automatically use the currently running event loop.","message":"Explicitly passing an `asyncio` event loop instance (e.g., `Channel(loop=my_loop)`) to the `Channel` constructor is generally discouraged as `asyncio` itself is phasing out explicit loop passing in favor of `asyncio.get_running_loop()`.","severity":"deprecated","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Ensure all calls to `async` methods or `async def` functions are prefixed with `await`. For top-level execution, use `asyncio.run()`.","cause":"Attempting to call an asynchronous method (e.g., `put`, `get`) on a Channel object without `await` inside an `async def` function, or calling an `async def` function as if it were a regular function.","error":"TypeError: object Channel cannot be awaited"},{"fix":"Design your producer logic to close the channel only when no more items will be sent. Consumers should handle the `ChannelClosed` exception, often by breaking out of a loop, or use `async for` which handles this implicitly.","cause":"Attempting to `put()` an item into a channel after `channel.close()` has been called, or attempting to `get()` from a channel that has been closed and is already empty.","error":"aiochannel.ChannelClosed: Channel is closed"}]}