Conversation
|
This PR is too large for me to read the diff on the web page. Can we split it? For example, Bump pyo3 to 0.26.0 deserves its own PR. I personally hate Makefile, can we use Justfile instead? |
|
Thank you! Welcome to pin me while this PR is ready. |
|
Hello team, I'm providing an update on the refactoring effort. While I've completed about 70% of the work, I've hit a significant roadblock with the The Core Issue: A Mismatch in Async Handling
Because our Rust functions are not literally Possible Paths ForwardI see two potential solutions to this problem: 1. Overhaul OpenDAL's Async Implementation (Not Recommended)We could refactor all our async methods to use However, I won't recommend this as it would be a substantial and invasive change to our core async logic, introducing complexity and potential risks, purely for the sake of stubs. Click to see a proof-of-concept `future_into_py_async` wrapper/// Spawns a future on the shared Tokio runtime and returns a Python awaitable.
/// Relies on the runtime from `pyo3-async-runtimes`.
pub async fn future_into_py_async<F, T>(fut: F) -> PyResult<T>
where
F: std::future::Future<Output = PyResult<T>> + Send + 'static,
T: Send + 'static,
{
let rt = pyo3_async_runtimes::tokio::get_runtime();
let handle = rt.handle().clone();
// Use a channel to bridge the result back from the spawned task
let (tx, rx) = tokio::sync::oneshot::channel();
// Spawn the future on the Tokio runtime
handle.spawn(async move {
let result = fut.await;
let _ = tx.send(result);
});
// Await the result from the channel
match rx.await {
Ok(result) => result,
Err(e) => Err(crate::errors::Unexpected::new_err(format!(
"Async task panicked or was dropped: {e}"
))),
}
}2. Enhance
|
|
Thank you @chitralverma for working on this! I didn’t take a close look at the changes to use std::{thread, time::Duration};
use futures::channel::oneshot;
use pyo3::prelude::*;
#[pyfunction]
#[pyo3(signature=(seconds, result=None))]
async fn sleep(seconds: f64, result: Option<Py<PyAny>>) -> Option<Py<PyAny>> {
let (tx, rx) = oneshot::channel();
thread::spawn(move || {
thread::sleep(Duration::from_secs_f64(seconds));
tx.send(()).unwrap();
});
rx.await.unwrap();
result
}What are the limitations? |
@Xuanwo your comment is in ref to point 1 in my message earlier. the snippet your shared is a simpler version of the difference between option 1 (self implemented Short answerThey’re similar in purpose but serve different roles. Long answerHigh-Level Comparison
Conceptual Difference: Two Approaches to Async BridgingThere's a fundamental difference in the design and use case between the standard
|
|
I think i should split this PR in smaller ones maybe, because if we have to try option 1, that will definitely need its own big PR |
Hi, I don't think they are the same thing. I thought we can do: use std::{thread, time::Duration};
use futures::channel::oneshot;
use pyo3::prelude::*;
#[pyfunction]
#[pyo3(signature=(seconds, result=None))]
async fn sleep(seconds: f64, result: Option<Py<PyAny>>) -> Option<Py<PyAny>> {
tokio::sleep(10s).await;
result
}Can we? |
#[pyo3(signature=(seconds, result=None))]
async fn sleep(&self, seconds: f64, result: Option<Py<PyAny>>) -> Option<Py<PyAny>> {
let (tx, rx) = tokio::sync::oneshot::channel();
let rt = pyo3_async_runtimes::tokio::get_runtime(); // <- tokio runtime injected
let handle = rt.handle().clone(); // <- injected runtime used to create a cheap handle
handle.spawn(async move {
tokio::time::sleep(tokio::time::Duration::from_secs_f64(seconds)).await;
let _ = tx.send(result);
});
rx.await.unwrap()
} |
|
Got it, thanks @chitralverma for the explanation. I agree that Jij-Inc/pyo3-stub-gen#326 is the right direction. Maybe we can collaborate with upstream to make it happen. |
|
raised Jij-Inc/pyo3-stub-gen#329 for jiff compatiiblity |
Which issue does this PR close?
Closes #6253
Rationale for this change
What changes are included in this PR?
Bump pyo3 to 0.26.0(chore(deps): bump the pyo3 group in /bindings/python with 2 updates #6631)Are there any user-facing changes?
Yes