Skip to main content

Go-style concurrency for Python. No async/await. No brokers. No boilerplate.

Project description

ryou

Go-style concurrency for Python. No async/await. No brokers. No boilerplate.

from ryou import ry, Chan, wait

@ry
def fetch(url: str) -> str:
    ...

h = ~fetch("https://example.com")
result, err = h.result()
if err:
    raise err
print(result)

Install

pip install ryou

Requires Python 3.12+, Linux/macOS only.

Concepts

Three primitives:

  • @ry — turns any function into a ryoutine. ~fn() spawns it concurrently.
  • Ry[T] — handle to a running ryoutine. .result() blocks until done, always returns (value, err).
  • Chan[T] — typed channel. send/recv block naturally, no busy loops.

Powered by gevent greenlets under the hood. IO ryoutines are cooperative greenlets. CPU ryoutines are forked processes. You never interact with gevent directly.

Quick Start

from ryou import ry, wait

@ry
def fetch(url: str) -> str:
    import urllib.request
    return urllib.request.urlopen(url).read(100).decode()

# spawn concurrently
h1 = ~fetch("https://example.com")
h2 = ~fetch("https://httpbin.org/html")

wait(h1, h2)

result, err = h1.result()
if err:
    print("failed:", err)
else:
    print(result)

~fn() spawns and returns a Ry[T] handle immediately. .result() blocks until the ryoutine finishes.

Channels

from ryou import ry, Chan, wait

ch = Chan[str]()

@ry
def producer():
    for i in range(5):
        ch.send(f"message {i}")
    ch.send(None)  # signal done

@ry
def consumer():
    while (msg := ch.recv()) is not None:
        print("got:", msg)

wait(~producer(), ~consumer())

Chan[T] is a typed, blocking queue. send blocks if full, recv blocks until an item is available. Goroutines yield while waiting — no busy loops.

Bounded channel:

ch = Chan[str](maxsize=10)  # blocks sender when full

CPU Bound Work

from ryou import ry, wait

@ry(cpu=True)
def crunch(n: int) -> int:
    return sum(range(n))

h = ~crunch(10**8)
result, err = h.result()
print(result)

cpu=True runs the function in a forked child process — true parallelism, no GIL. IO and CPU ryoutines can run simultaneously.

Error Handling

.result() never raises. It always returns (value, err):

h = ~fetch("https://bad-url")
result, err = h.result()
if err:
    print("error:", err)  # handle it
else:
    print(result)

Wait

wait()           # wait for all running ryoutines
wait(h1, h2)     # wait for specific handles

API Reference

@ry

@ry
def fn() -> T: ...          # IO bound, runs on greenlet

@ry(cpu=True)
def fn() -> T: ...          # CPU bound, runs in forked process

Ry[T]

h = ~fn()                              # spawn
val, err = h.result()                  # block until done, (T | None, Exception | None)

Chan[T]

ch = Chan[T]()              # unbounded
ch = Chan[T](maxsize=10)    # bounded

ch.send(value)              # blocks if full
value = ch.recv()           # blocks until item available

wait

wait()          # wait for all
wait(h1, h2)    # wait for specific handles

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ryou-0.1.0.tar.gz (3.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ryou-0.1.0-py3-none-any.whl (4.4 kB view details)

Uploaded Python 3

File details

Details for the file ryou-0.1.0.tar.gz.

File metadata

  • Download URL: ryou-0.1.0.tar.gz
  • Upload date:
  • Size: 3.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.9

File hashes

Hashes for ryou-0.1.0.tar.gz
Algorithm Hash digest
SHA256 25d3f562b22e9ebcc957d06ef43f1dc577a9d17c2b91b22240998c44d2d3168c
MD5 e1c9c22b39fbb586b33b488ea7622993
BLAKE2b-256 dcca0d3c43f062cb9df6ca3f8a932f770ae28e8dfc49726d5771ca68293184d1

See more details on using hashes here.

File details

Details for the file ryou-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: ryou-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 4.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.9

File hashes

Hashes for ryou-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f9de8789ee5ee3ab5529a957ea8c6a9b4a12d8c2e27f62358fcda4294ef063e9
MD5 8a543a40bd8a53746c224f792071aa50
BLAKE2b-256 61e5f4aee47a4b1d0fa1148d39be31e11b2aa9da46b6f67dd677b2dfa102bfcd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page