Can't run on a single-threaded executor, as the manual polling of `run_instance` blocks the executor
Is your issue REALLY a bug?
- [x] My issue is indeed a bug!
- [x] I am not crazy! I will not fill out this form just to ask a question or request a feature. Pinky promise.
Is there an existing issue for this?
- [x] I have searched the existing issues.
Is this issue related to iced?
- [x] My hardware is compatible and my graphics drivers are up-to-date.
What happened?
I tread running a single-threaded executor:
fn main() {
iced::application(App::default, App::update, App::view)
.executor::<LocalTokioExecutor>()
.title("my app")
.decorations(true)
.theme(App::theme)
.run()
.unwrap();
}
struct LocalTokioExecutor {
runtime: tokio::runtime::Runtime,
}
impl iced::executor::Executor for LocalTokioExecutor {
#[inline]
fn new() -> Result<Self, Error>
where
Self: Sized,
{
tracing::info!("Creating local tokio runtime");
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
//.build_local(tokio::runtime::LocalOptions::default())
.build()
.map(|runtime| Self { runtime });
tracing::info!("Created local tokio runtime");
rt
}
#[inline]
fn spawn(&self, future: impl Future<Output = ()> + iced_futures::MaybeSend + 'static) {
eprintln!("Trigger spawn");
self.runtime.spawn(async move {
eprintln!("Spawning future");
future.await;
eprintln!("Future finished");
});
}
#[inline]
fn block_on<T>(&self, future: impl Future<Output = T>) -> T {
eprintln!("Blocking on future");
let res = self.runtime.block_on(future);
eprintln!("Future finished");
res
}
#[inline]
fn enter<R>(&self, f: impl FnOnce() -> R) -> R {
eprintln!("Entering runtime");
let _g = self.runtime.enter();
let res = f();
eprintln!("Exiting runtime");
res
}
}
No window pops up.
After looking at the code, I see that spawned futures are never picked up and executed.
After following it further, it's a bit of a systemic problem. The executor (if running CurrentThread) is the thread that starts and drives the event-loop handler.
That gets stuck perpetually polling run_instance and doing nothing else, no background tasks are making any progress.
I think this would need a refactor of the main event handler to solve, but I'll try to fiddle around with it a bit if I find the time.
F.E. this solves it:
struct LocalTokioExecutor {
runtime: tokio::runtime::Handle,
}
impl iced::executor::Executor for LocalTokioExecutor {
#[inline]
fn new() -> Result<Self, Error>
where
Self: Sized,
{
tracing::info!("Creating local tokio runtime");
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()?;
let handle = rt.handle().clone();
std::thread::spawn(move || rt.block_on(async { tokio::signal::ctrl_c().await }));
tracing::info!("Created local tokio runtime");
Ok(Self { runtime: handle })
}
...
Because then a thead can drive what's spawned onto the runtime. That does make it non single-threaded though. So I wouldn't call that a proper workaround.
What is the expected behavior?
Everything works as expected from a multi-threaded executor
Version
master
Operating System
Linux
Do you have any log output?