TaskCompletionSource для нескольких объектов, ожидающих одной и той же задачи

Мне интересно, было бы уместно использовать класс TaskCompletionSource в следующем примере:

Исходный код/без TaskCompletionSource

public async Task GetData() 
{
    if (!IsLoaded) 
    {
        MyList = await Mediator.Send(new GetData());
        IsLoaded = true;
    }
}

Эта функция доступна как часть одноэлементной службы в моем веб-приложении .NET Core. Несколько объектов могут использовать записи в MyList и будут ожидать функции GetData() перед использованием списка.

Из примера функции видно, что метод может вызываться несколько раз, в то время как первый вызов все еще ожидает результата запроса посредника. Мне нужно решение, позволяющее нескольким объектам ожидать одну и ту же задачу. Так уместно ли использовать объект TaskCompletionSource для этой цели?

Рефакторинг с использованием TaskCompletionSource

private TaskCompletionSource getDataTask;

public async Task VerifyDataIsLoaded() 
{
    if (getDataTask == null) 
    {
        getDataTask = new TaskCompletionSource();
        Task.Factory.StartNew(async () => 
        {
            await GetData();
            getDataTask.TrySetResult();
        }
    }
    return getDataTask.Task;
}

private async Task GetData() 
{
    MyList = await Mediator.Send(new GetData());
}

Это должно привести к тому, что первый вызов VerifyDataIsLoaded() создаст экземпляр объекта TaskCompletionSource getDataTask, запустит функцию GetData() в новой многопоточной задаче и вернет свойство getDataTask.Task.

Теперь, если какие-либо другие объекты вызывают VerifyDataIsLoaded(), пока функция GetData() ожидает возврата от объекта Mediator, все они будут ожидать одну и ту же задачу и предотвратят любые избыточные вызовы GetData.

Мысли?? ... плохая идея?? лучший способ??


person Thrifty2100    schedule 20.07.2021    source источник
comment
Я думаю, вы только что упустили один очень важный аспект: что, если GetData не сработает? Потому что вы вызываете огонь и забываете моду, поэтому, если она потерпит неудачу, вы никогда не узнаете, и getDataTask никогда не завершится.   -  person Peter Csala    schedule 21.07.2021
comment
Вероятно, это то, что вы хотите: Принудительно вызывать асинхронный метод один раз.   -  person Theodor Zoulias    schedule 21.07.2021


Ответы (1)