我有一个由 ApiClient
类的多个使用者同时调用的方法。我想阻止对该方法的并发调用,直到第一个调用完成,然后短路其余的调用。
在下面的伪代码中,多个线程可能调用RefreshApiTokenAsync()
。我想阻止除一次调用内部 this.GetNewApiTokenAsync()
方法之外的所有调用。这将避免代码在多个线程上检测到过期的 ApiToken,然后尝试多次刷新它的情况。
public class ApiClient
{
private static readonly ConcurrentDictionary<string, string> ApiTokens = new ConcurrentDictionary<string, string>();
public async Task DoSomething()
{
// Call third party API and then detect an out of date API token.
// The CallThirdPartyApi uses the token in the ApiTokens ConcurrentDictionary
var result = await CallThirdPartyApi();
if (result.ApiTokenOutOfDate) {
await this.RefreshApiTokenAsync();
result = await CallThirdPartyApi();
}
return result;
}
private async Task<string> RefreshApiTokenAsync()
{
string newToken = await this.GetNewApiTokenAsync();
return ApiTokens.AddOrUpdate("ApiToken", newToken, (key, value) => newToken);
}
}
我相信这被认为是去抖动,但我不确定如何实现这一点。
最佳答案
您可以存储刷新 token 任务并将其返回给调用者。 token 刷新后,调用者可以继续执行。这是示例任务存储:
private static readonly ConcurrentDictionary<string, Lazy<Task>> RefreshTokenTasks = new ConcurrentDictionary<string, Lazy<Task>>();
刷新 token 方法可以是这样的:
private Task RefreshApiTokenAsync()
{
return RefreshTokenTasks.GetOrAdd("refreshTokenTask", _ => new Lazy<Task>( async () =>
{
try
{
string newToken = await this.GetNewApiTokenAsync();
ApiTokens.AddOrUpdate("ApiToken", newToken, (key, value) => newToken);
}
finally
{
Lazy<Task> refreshTask;
RefreshTokenTasks.TryRemove("refreshTokenTask", out refreshTask);
}
}, LazyThreadSafetyMode.ExecutionAndPublication)).Value;
}
关于c# - 阻止并发调用者并从异步方法返回单个结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38401227/