Progress bar's tag id keeps being too small #1548
|
(Already poste on discord in the #Help channel, since no one answered I'm trying here) Context:I am trying to write an open source application which helps in downloading files from one machine to another on the same network/LAN. You may find the current code source here: https://github.com/yifu/pushpop. Problem:The progress bar, for the download, never gets updated, or when it does then it is quite erratic. I would say it's always below the real total of downloaded bytes. When I debug this application, with delve, then I observe that the tag inside the progress.go (line 209-215) As a consequence the progress bar never gets updated (quasi never), since the resulting command is nil (nearly always). Questions:What I am doing wrong here? It looks like the messages are somehow "buffered" before being sent to the main application thread, thus the progress model tag is incremented too much before the first message has the opportunity to be processed. Is there some "buffering" issues? Or ... Can it be a bug? May a fix could be the following? |
Replies: 1 comment
|
Your diagnosis is exactly right — you're hitting the Why this happens with a file-copy loopEvery Two fixes, pick oneOption A: use If you don't specifically need the smooth animated fill, this is one line: // In your View() method, don't store percent on the progress model.
// Just compute it and pass in:
return m.progress.ViewAs(m.downloadedBytes / float64(m.totalBytes))
For a network-download progress bar, Option B: throttle If you want to keep the tweened animation, rate-limit your // In your download goroutine:
var lastUpdate time.Time
for {
n, err := reader.Read(buf)
// ...
downloaded += int64(n)
if time.Since(lastUpdate) > 33*time.Millisecond { // ~30 Hz
program.Send(progressMsg{percent: float64(downloaded) / float64(total)})
lastUpdate = time.Now()
}
}Then in your Update, turn Diagnostic I'd runTo confirm it's really the tag race and not something else, add a print right before the dropped FrameMsg: case progress.FrameMsg:
// quick diagnostic
fmt.Fprintf(os.Stderr, "FrameMsg id=%d tag=%d (model id=%d tag=%d)\n",
msg.id, msg.tag, m.progress.ID(), m.progress.Tag())
newProgress, cmd := m.progress.Update(msg)You'll see the tags drifting. Once you apply either fix, they stay aligned. Why
|
Your diagnosis is exactly right — you're hitting the
progress.Model's tag-versioning guard. It's not a bug, it's the mechanism that prevents stale FrameMsgs from glitching the animation when multipleSetPercentcalls arrive in quick succession. The tag check discards messages older than the latest target, which is what happens when you drive progress updates faster than the frame-tick rate.Why this happens with a file-copy loop
Every
SetPercent(x)bumps the internal tag and schedules a tween. If you callSetPercentagain before the previous tween emits its first FrameMsg, the tag bumps a second time — and when the tween's frame finally arrives, it's stamped with the old tag and gets disc…