|
Using:
TOML:
Description: Dioxus runs inside my own Tokio Runtime (6 Worker Threads) Previously I startet a worker Thread with [ Now the Dioxus Task site: I need to wait for incoming message from my service task. Like this: This is the "batch" version. I tried this to avoid message flooding at the Dioxus task. Inside a component, it looks like this: This is an example. Now, if I start my appllication, it works, as expected. I'm able to send a message to my service task and I can receive a message from the service task. But, at that moment I start a library scan, the workload becomes more heavy with more incoming messages on the Dioxus site. This forces Dioxus to freez at some point. Sometimes a scan can be finished, without any errors, sometimes not. I the scan task is completed and starting a second run, the UI freezes. I also tried to use [ My service task runs in the background. This task does not freeze. It's only the UI. Any ideas? |
Replies: 5 comments
|
I rebuilt your exact pattern headlessly against the dioxus v0.7.10 source (VirtualDom driven the way dioxus's own core tests drive it: rebuild, wait_for_work, render_immediate, no display needed) and put it under a message flood. Three results, and together they point very precisely at where your freeze lives. First, the good news: the code you posted is innocent. The future-with-recv_many loop, the signal.set of the buffer, and the effect that reads Now the mechanism that does produce your exact symptom. In v0.7.10, The critical part: you wrote "This is an example" about your effect body, and one entirely natural line turns your innocent example into the freeze. I mutated the verified-clean version by adding only a guard read: Message::LibraryScanStarted => {
if !*scan_running.read() { // this read subscribes the effect to scan_running
scan_running.set(true);
}
}That single change livelocked the identical harness: about 24,000 render-churn cycles, the recv future starved at 64 ticks, then the terminal spin. The guard reads So the audit for your real code: in every
If the audit finds nothing, the discriminating next step is binary search: comment out effect bodies one at a time under load; the freeze will vanish with a specific one, and the read-write pair will be inside it. Happy to share the headless harness (about 150 lines, no GUI required) if you want to reproduce any of this or test your real effect bodies directly. One caveat for honesty: I ran this on Linux against the shared core scheduler, not on Windows with the WebView attached. But the livelock measured here never yields the driving thread at all, which is renderer-independent, and it reproduces your symptom signature exactly. |
|
Thank you for your answer. So I started to comment out alot of code. At the End I removed any custom hook which contains a listener. Except one single. This code is only executed if I click a button. At that moment a Message is send to my Settings Server. It handles the change of a single setting and broadcast the change to any subscriber. To filter out a single setting, you could proceed as follows This code is part of another custom hook. This hook uses the use_settings_message() hook above. I tried it with a memo (general works) as well as with a use_effect (also works). I think, there is no issue with both version of filtering. Both are commented out. To eliminate the possibility that there is an issue here. The UI is still freezing. At any point there is no Signal::read(). It is, that at this moment I use the use_future hook (from above) the UI starts freezing after a while. Once I’ve changed my settings enough. At that moment, I comment out the function body (no call of use_future() anymore), I can change my settings as often as I want. Ok... back to my use_settings_message() hook. The last custom hook with a body. I tried the following And yes... at that moment I comment out the loop [ |
|
Ok, I did a simple test Works as intended. But I have a quest. What happend to the [ |
|
This is excellent debugging, and I want to update honestly first: your data falsifies my first mechanism as the cause of YOUR freeze. The read-write effect livelock I measured is real, but you removed every consumer, every First your direct question, because it is load-bearing: Now look at the asymmetry you found, because it explains itself once you see the channel-close semantics. Without the recv loop, your future completes immediately, the You are almost certainly not alone in this, and that is the strongest evidence of all: there is an open dioxus issue, #5679, titled "[desktop] UI freezes in an existing Tokio runtime after cooperative budget exhaustion." That is your exact configuration (desktop, your own multi-thread runtime) and your exact symptom. Read it before you do anything else; if it matches, your case is a data point on a known bug, not a mistake in your code. The related merged PR #5430, "add wakeup callback for external event loop integration," is the shape of the real fix: it is about making the desktop event loop and the async runtime wake each other correctly, which is precisely the seam your freeze lives on. That reframes the mechanism from "your channel" to "does the desktop scheduler keep polling your recv future." I tested the consequence of it not doing so, at the tokio layer, with a manual executor whose waker delivery I deliberately break after N wakes (modeling the scheduler ceasing to re-poll). The result: the bounded-channel drain halts, and how much it drains before halting scales linearly with both the number of wakes delivered and the channel capacity (measured: drain point moved from ~500 to ~1500 as I varied those). The instant the drain halts, the sender's Three questions make your next post decisive:
The clean control matters too, so you do not chase tokio itself: with a correctly delivering waker (the executor services every wake), the same foreign-executor recv loop drained 100000 of 100000 messages at capacities 8, 32, 128, and 512, no stall. So the answer to "has tokio a bug?" is a measured no: the primitive is fine when it is polled. The freeze appears only when wake delivery to the recv future stops, which is a scheduler-integration property, not a channel property, and is what #5679 and PR #5430 are about. Fixes, in the order I would take them:
Honest scope note: I could not compile dioxus 0.7 in today's environment (toolchain too old here), so the "task stops being polled" step is inference from your measurements rather than something I reproduced at the dioxus layer; the tokio layer is measured as clean. Your answers to the three questions above, especially the thread dump, will confirm or kill the model in one post. |
|
One answer: Oh wow.... #5679, this could be the answer. It needs further testings. But my application runs with many library scans now. Without any issues. I let it run for a while, to make sure this was the solution. At the moment my application runs for around 1300s with a library scan every 20s. What have I changed? EditThis could also the explanation why [ |
This is excellent debugging, and I want to update honestly first: your data falsifies my first mechanism as the cause of YOUR freeze. The read-write effect livelock I measured is real, but you removed every consumer, every
signal.set, every tracked read, and it still froze; so it is not this. What your three experiments select instead is more interesting, and your own pure-tokio test is one of the pieces of evidence.First your direct question, because it is load-bearing:
recv().awaitcannot hang because a sender is stuck; it parks until a message arrives or everySenderis dropped, nothing else. The hang risk in bounded mpsc lives entirely on the send side:send().awaiton a full channel…