Improve async queue work
This is something I've been contemplating since before the 41.0 release and something which I want fixed asap and before the 41.1 release (especially the flatpak), to provide an optimal first use experience.
This is a bit of a braindump to clear my thoughts.
In quite late stages of the 41 cycle I added several async related fixes. I made several blocking functions async and added a queue to lighten the workload. This did great things for Musics responsiveness especially on startup, when Musically literally tries to load almost everything at once, via Grilo, Tracker, MediaArt and GStreamer while doing simultaneously lookups for art not available locally. This should also help reports of too much open file handles, which were frequent on large collections as we limit the amount of concurrent tasks reading/writing files.
Around the same time @jfelder's work on adding artist art to
ArtistsView got merged, which also lead to lookup of all artist art as well. This loading of artist art is in practice quite slow and seems to be heavy on Grilo/Tracker (besides being blocking in Grilo (grilo-plugins!117 (merged))).
Also there seems to be a general slowness around loading playlists, which could use some further investigation. I am not completely sure if it is not just another expression of the async madness.
All of this together results in long running tasks hogging the
AsyncQueue after a short while in my experience. Which is suboptimal as Music is responsive in feel (no UI blocking), but not in action: it takes a long time to load certain elements like art, but also opening of new albums, artists, searches, et cetera on startup.
I prefer to use a minimal amount of additional workarounds to achieve the goal of a quick loading and responsive UI, it should not overcomplicate the whole loading process.
Use a priority pool as part of the
AsyncQueue, which can be triggered by the widgets when they start loading a specific item. eg. when loading an
AlbumWidget, set the
CoreAlbum in the
PriorityPool. This is checked when the next
AsyncQueue dispatch is called and then a special pool is kept open for priority tasks.
Of course these priority tasks may turn out to be long running as well, so if they take too long pass them to the default active_queue (this may end up bigger than
_max_sync, but that is probably not a big problem as no other tasks should get added to the pool until it falls below the treshhold again).
Adaptive queue size
For non-I/O tasks it should be possible to enlarge/shrink the size of the queue while they get handled fast enough. eg. if the active pool is always (partially) empty the next dispatch the pool size could be increased (and shrunk vice-versa). Up to an upper/lower limit.
For I/O tasks it should be set to a sensible default (the current
_max_size is probably a bit low), but not too much as it might open us again to too much open files issues.
If we could figure out if a task is blocked on local I/O, we could probably be smarter, but currently I see no way to do this and would need another rework of how we handle art.
Cancelling long-running tasks and re-queue them later
This is something that might be possible, but looks quite involved to me. If we encounter long running tasks in the default async queue, cancel them and add them to a backup queue.