Скажем, у нас есть первый вызов GetDefaultData (GetData() выполняется в 100 мс), а затем у нас есть 10 вызовов (GetDefaultData() за 10 мс). Я хочу, чтобы этот остаток звонков получил тот же ответ, что и первый.
Похоже, вы хотите класс Lazy<T>
.
public class YourClass
{
private readonly Lazy<Data> _lazyData;
public YourClass()
{
_lazyData = new Lazy<Data>(() => GetData());
}
private Data GetDefaultData()
{
return _lazyData.Value;
}
public Data GetData()
{
//...
}
}
Первый поток для вызова GetDefaultData()
будет работать GetData()
, когда она попадает _lazyData.Value
, все остальные из потоков будет блокировать на вызов _lazyData.Value
до первой резьбы отделок и использовать результат от вызова этого первого потока. GetData()
будет вызываться только один раз.
Если вы не хотите блокировать вызов, вы можете легко сделать класс AsyncLazy<T>
, который использует потоки внутри.
public class AsyncLazy<T> : Lazy<Task<T>>
{
public AsyncLazy(Func<T> valueFactory) :
base(() => Task.Run(valueFactory))
{
}
public AsyncLazy(Func<Task<T>> taskFactory, bool runFactoryInNewTask = true) :
base(() => runFactoryInNewTask ? Task.Run(taskFactory) : taskFactory())
{
}
//This lets you use `await _lazyData` instead of doing `await _lazyData.Value`
public TaskAwaiter<T> GetAwaiter()
{
return Value.GetAwaiter();
}
}
Тогда ваш код становится (я также сделал GetData функцию асинхронной тоже, но перегруженные AsyncLazy
пусть это будет либо или)
public class YourClass
{
private readonly AsyncLazy<Data> _lazyData;
public YourClass()
{
_lazyData = new AsyncLazy<Data>(() => GetData(), false);
}
private async Task<Data> GetDefaultData()
{
//I await here to defer any exceptions till the returned task is awaited.
return await _lazyData;
}
public Task<Data> GetData()
{
//...
}
}
EDIT: Там некоторые возможные проблемы с AsyncLazy , see here.
С учетом предоставленного кода для каждого вызова функции GetDefaultData() будет развернута другая задача. Независимо от того, является ли значение 'data.Result' одинаковым между вызовами, зависит от того, что происходит внутри' GetData' –
GetData() собирает данные внутри оператора блокировки. –
Вы хотите позвонить один раз и прочитать много? Или вы хотите, чтобы данные обновлялись после X миллисекунд? –