Skip to content

Commit ebd1bc2

Browse files
authored
Merge pull request #1 from marcomq/mm/pyo3_asyncio
Mm/pyo3 asyncio
2 parents 094cd5c + 0d3d779 commit ebd1bc2

File tree

7 files changed

+461
-45
lines changed

7 files changed

+461
-45
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ categories = ["api-bindings", "asynchronous", "external-ffi-bindings"]
1414
dunce = "1.0.4"
1515
serde_json = "1.0.114"
1616
thiserror = "2.0"
17-
tokio = { version = "1.36.0", features = ["sync", "macros"] }
17+
once_cell = "1.19"
18+
tokio = { version = "1.47.0", features = ["sync", "macros", "rt", "rt-multi-thread"] }
1819

1920
[features]
2021
default = ["pyo3"]
@@ -27,18 +28,16 @@ version = "0.26.0"
2728
features = ["auto-initialize"]
2829
optional = true
2930

30-
[dev-dependencies]
31-
tempfile = "3"
3231
[dependencies.rustpython-vm]
3332
version = "0.4.0"
3433
optional = true
3534
features = ["threading", "serde", "importlib"]
35+
3636
[dependencies.rustpython-stdlib]
3737
version = "0.4.0"
3838
optional = true
3939
features = ["threading"]
4040

41-
# The `full` feature for tokio is needed for the tests
42-
[dev-dependencies.tokio]
43-
version = "1"
44-
features = ["full"]
41+
[dev-dependencies]
42+
tempfile = "3"
43+
tokio = { version = "1.47.0", features = ["full"] }

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,44 @@ def greet(name):
5050
println!("{}", result2.as_str().unwrap()); // Prints: Hello World! Called 2 times from Python.
5151
}
5252
```
53+
54+
### Async Python Example
55+
56+
```rust
57+
use async_py::PyRunner;
58+
59+
#[tokio::main]
60+
async fn main() {
61+
let runner = PyRunner::new();
62+
let code = r#"
63+
import asyncio
64+
counter = 0
65+
66+
async def add_and_sleep(a, b, sleep_time):
67+
global counter
68+
await asyncio.sleep(sleep_time)
69+
counter += 1
70+
return a + b + counter
71+
"#;
72+
73+
runner.run(code).await.unwrap();
74+
let result1 = runner.call_async_function("add_and_sleep", vec![5.into(), 10.into(), 1.into()]);
75+
let result2 = runner.call_async_function("add_and_sleep", vec![5.into(), 10.into(), 0.1.into()]);
76+
let (result1, result2) = tokio::join!(result1, result2);
77+
assert_eq!(result1.unwrap(), Value::Number(17.into()));
78+
assert_eq!(result2.unwrap(), Value::Number(16.into()));
79+
}
80+
```
81+
Both function calls are triggered to run async code at the same time. While the first call waits for the sleep,
82+
the second can already start and also increment the counter first. Therefore,
83+
result1 will wait longer and compute 5 + 10 + 2, while the result2 can compute 5 + 10 + 1.
84+
85+
Each call will use its own event loop. This may not be very efficient and changed later.
86+
87+
Make sure to use `call_async_function` for async python functions. Using `call_function` will
88+
probably raise an error.
89+
`call_async_function` is not available for RustPython.
90+
5391
### Using a venv
5492
It is generally recommended to use a venv to install pip packages.
5593
While you cannot switch the interpreter version with this crate, you can use an

0 commit comments

Comments
 (0)