1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-29 02:29:54 +08:00

Add debounce to difficulty calculation operations in churn scenarios

This commit is contained in:
Dean Herbert
2025-05-19 15:55:38 +09:00
Unverified
parent c339977e98
commit 192a1642d4
7 changed files with 23 additions and 16 deletions
@@ -141,7 +141,7 @@ namespace osu.Game.Tests.Visual.SongSelect
}
}
public override async Task<StarDifficulty?> GetDifficultyAsync(IBeatmapInfo beatmapInfo, IRulesetInfo? rulesetInfo = null, IEnumerable<Mod>? mods = null, CancellationToken cancellationToken = default)
public override async Task<StarDifficulty?> GetDifficultyAsync(IBeatmapInfo beatmapInfo, IRulesetInfo? rulesetInfo = null, IEnumerable<Mod>? mods = null, CancellationToken cancellationToken = default, int debounceDelay = 0)
{
if (blockCalculation)
{
@@ -149,7 +149,7 @@ namespace osu.Game.Tests.Visual.SongSelect
await calculationBlocker.Task.ConfigureAwait(false);
}
return await base.GetDifficultyAsync(beatmapInfo, rulesetInfo, mods, cancellationToken).ConfigureAwait(false);
return await base.GetDifficultyAsync(beatmapInfo, rulesetInfo, mods, cancellationToken, 0).ConfigureAwait(false);
}
}
}
@@ -125,7 +125,7 @@ namespace osu.Game.Tests.Visual.UserInterface
public StarDifficulty? Difficulty { get; set; }
public override Task<StarDifficulty?> GetDifficultyAsync(IBeatmapInfo beatmapInfo, IRulesetInfo? rulesetInfo = null, IEnumerable<Mod>? mods = null,
CancellationToken cancellationToken = default)
CancellationToken cancellationToken = default, int computationDelay = 0)
=> Task.FromResult(Difficulty);
}
}
+10 -7
View File
@@ -98,12 +98,13 @@ namespace osu.Game.Beatmaps
/// </summary>
/// <param name="beatmapInfo">The <see cref="BeatmapInfo"/> to get the difficulty of.</param>
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops updating the star difficulty for the given <see cref="BeatmapInfo"/>.</param>
/// <param name="computationDelay">A delay in milliseconds before performing the </param>
/// <returns>A bindable that is updated to contain the star difficulty when it becomes available. Will be null while in an initial calculating state (but not during updates to ruleset and mods if a stale value is already propagated).</returns>
public IBindable<StarDifficulty?> GetBindableDifficulty(IBeatmapInfo beatmapInfo, CancellationToken cancellationToken = default)
public IBindable<StarDifficulty?> GetBindableDifficulty(IBeatmapInfo beatmapInfo, CancellationToken cancellationToken = default, int computationDelay = 0)
{
var bindable = new BindableStarDifficulty(beatmapInfo, cancellationToken);
updateBindable(bindable, currentRuleset.Value, currentMods.Value, cancellationToken);
updateBindable(bindable, currentRuleset.Value, currentMods.Value, cancellationToken, computationDelay);
lock (bindableUpdateLock)
trackedBindables.Add(bindable);
@@ -118,13 +119,14 @@ namespace osu.Game.Beatmaps
/// <param name="rulesetInfo">The <see cref="IRulesetInfo"/> to get the difficulty with.</param>
/// <param name="mods">The <see cref="Mod"/>s to get the difficulty with.</param>
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops computing the star difficulty.</param>
/// <param name="computationDelay">In the case a cached lookup was not possible, a value in milliseconds of to wait until performing potentially intensive lookup.</param>
/// <returns>
/// The requested <see cref="StarDifficulty"/>, if non-<see langword="null"/>.
/// A <see langword="null"/> return value indicates that the difficulty process failed or was interrupted early,
/// and as such there is no usable star difficulty value to be returned.
/// </returns>
public virtual Task<StarDifficulty?> GetDifficultyAsync(IBeatmapInfo beatmapInfo, IRulesetInfo? rulesetInfo = null,
IEnumerable<Mod>? mods = null, CancellationToken cancellationToken = default)
public virtual Task<StarDifficulty?> GetDifficultyAsync(IBeatmapInfo beatmapInfo, IRulesetInfo? rulesetInfo = null, IEnumerable<Mod>? mods = null,
CancellationToken cancellationToken = default, int computationDelay = 0)
{
// In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset.
rulesetInfo ??= beatmapInfo.Ruleset;
@@ -139,7 +141,7 @@ namespace osu.Game.Beatmaps
return Task.FromResult<StarDifficulty?>(new StarDifficulty(beatmapInfo.StarRating, (beatmapInfo as IBeatmapOnlineInfo)?.MaxCombo ?? 0));
}
return GetAsync(new DifficultyCacheLookup(localBeatmapInfo, localRulesetInfo, mods), cancellationToken);
return GetAsync(new DifficultyCacheLookup(localBeatmapInfo, localRulesetInfo, mods), cancellationToken, computationDelay);
}
protected override Task<StarDifficulty?> ComputeValueAsync(DifficultyCacheLookup lookup, CancellationToken cancellationToken = default)
@@ -206,11 +208,12 @@ namespace osu.Game.Beatmaps
/// <param name="rulesetInfo">The <see cref="IRulesetInfo"/> to update with.</param>
/// <param name="mods">The <see cref="Mod"/>s to update with.</param>
/// <param name="cancellationToken">A token that may be used to cancel this update.</param>
private void updateBindable(BindableStarDifficulty bindable, IRulesetInfo? rulesetInfo, IEnumerable<Mod>? mods, CancellationToken cancellationToken = default)
/// <param name="computationDelay">In the case a cached lookup was not possible, a value in milliseconds of to wait until performing potentially intensive lookup.</param>
private void updateBindable(BindableStarDifficulty bindable, IRulesetInfo? rulesetInfo, IEnumerable<Mod>? mods, CancellationToken cancellationToken = default, int computationDelay = 0)
{
// GetDifficultyAsync will fall back to existing data from IBeatmapInfo if not locally available
// (contrary to GetAsync)
GetDifficultyAsync(bindable.BeatmapInfo, rulesetInfo, mods, cancellationToken)
GetDifficultyAsync(bindable.BeatmapInfo, rulesetInfo, mods, cancellationToken, computationDelay)
.ContinueWith(task =>
{
// We're on a threadpool thread, but we should exit back to the update thread so consumers can safely handle value-changed events.
+7 -3
View File
@@ -35,8 +35,9 @@ namespace osu.Game.Database
/// Retrieve the cached value for the given lookup.
/// </summary>
/// <param name="lookup">The lookup to retrieve.</param>
/// <param name="token">An optional <see cref="CancellationToken"/> to cancel the operation.</param>
protected async Task<TValue?> GetAsync(TLookup lookup, CancellationToken token = default)
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> to cancel the operation.</param>
/// <param name="computationDelay">In the case a cached lookup was not possible, a value in milliseconds of to wait until performing potentially intensive lookup.</param>
protected async Task<TValue?> GetAsync(TLookup lookup, CancellationToken cancellationToken = default, int computationDelay = 0)
{
if (CheckExists(lookup, out TValue? existing))
{
@@ -44,7 +45,10 @@ namespace osu.Game.Database
return existing;
}
var computed = await ComputeValueAsync(lookup, token).ConfigureAwait(false);
if (computationDelay > 0)
await Task.Delay(computationDelay, cancellationToken).ConfigureAwait(false);
var computed = await ComputeValueAsync(lookup, cancellationToken).ConfigureAwait(false);
statistics.Value.MissCount++;
@@ -246,7 +246,7 @@ namespace osu.Game.Screens.Select.Carousel
if (Item?.State.Value != CarouselItemState.Collapsed)
{
// We've potentially cancelled the computation above so a new bindable is required.
starDifficultyBindable = difficultyCache.GetBindableDifficulty(beatmapInfo, (starDifficultyCancellationSource = new CancellationTokenSource()).Token);
starDifficultyBindable = difficultyCache.GetBindableDifficulty(beatmapInfo, (starDifficultyCancellationSource = new CancellationTokenSource()).Token, 200);
starDifficultyBindable.BindValueChanged(d =>
{
starCounter.Current = (float)(d.NewValue?.Stars ?? 0);
+1 -1
View File
@@ -202,7 +202,7 @@ namespace osu.Game.Screens.SelectV2
var beatmap = (BeatmapInfo)Item.Model;
starDifficultyBindable = difficultyCache.GetBindableDifficulty(beatmap, starDifficultyCancellationSource.Token);
starDifficultyBindable = difficultyCache.GetBindableDifficulty(beatmap, starDifficultyCancellationSource.Token, 200);
starDifficultyBindable.BindValueChanged(_ => updateDisplay(), true);
}
@@ -238,7 +238,7 @@ namespace osu.Game.Screens.SelectV2
var beatmap = (BeatmapInfo)Item.Model;
starDifficultyBindable = difficultyCache.GetBindableDifficulty(beatmap, starDifficultyCancellationSource.Token);
starDifficultyBindable = difficultyCache.GetBindableDifficulty(beatmap, starDifficultyCancellationSource.Token, 200);
starDifficultyBindable.BindValueChanged(_ => updateDisplay(), true);
}