#c# #asynchronous #task-parallel-library
#c# #асинхронный #задача-параллельная-библиотека
Вопрос:
Я пришел к следующему коду в одном из моих базовых классов, который отлично работает (см. Комментарий):
private static Dictionary<string, TItem> _cache;
protected Dictionary<string, TItem> Cache
{
get
{
if (_cache == null)
{
// Instead of FillCacheAsync().Wait(); I now do the following:
var reset = new AutoResetEvent(false);
Task.Run(
async () =>
{
await FillCacheAsync();
reset.Set();
});
reset.WaitOne();
}
return _cache;
}
}
private async Task FillCacheAsync()
{
_cache = new Dictionary<string, TItem>();
await InternalCacheFillAsync();
}
// This is not part of the question.
protected abstract Task InternalCacheFillAsync();
Является ли это хорошим решением проблемы, из-за которой отложенное свойство не может быть помечено как async
? Здесь у меня были огромные проблемы даже с использованием ConfigureAwait(false)
на месте.
Комментарии:
1. Почему бы не использовать simple
FillCacheAsync().Wait()
? В чем преимущество этой дополнительной работы с событием.2. @Honza: Как я писал в своем посте, это приводит к серьезным проблемам, даже если я тщательно использовал
ConfigureAwait
весь путь вниз.3.
AutoResetEvent
На самом деле в этом нет необходимости; лучшим решением для блокировки было быTask.Run(() => FillCacheAsync()).GetAwaiter().GetResult()
. Было бы лучше вообще не блокировать — например,AsyncLazy<T>
.
Ответ №1:
Стивен Клири освещает именно эту тему свойств async в своем блоге.
Он предлагает простой способ удовлетворить вашу потребность в свойстве cached value, которое будет кэшироваться асинхронным способом с использованием AsyncLazy<T>
его библиотеки AsyncEx, это избавит вас от необходимости использовать AutoResetEvent и упростит ваш код.
Простой пример вашего класса с кэшированным свойством:
public class SomeClass
{
static SomeClass()
{
Cache = new AsyncLazy<Dictionary<string, TItem>>(GetCacheAsync);
}
public static AsyncLazy<Dictionary<string, TItem>> Cache { get; }
private static Task<Dictionary<string, TItem>> GetCacheAsync()
{
....
}
}.
И доступ к значению кэшированного свойства:
Dictionary<string, TItem> value = await SomeClass.Cache;
Комментарии:
1. Хороший материал! Итак, я предполагаю, что мое решение не такое уж и сложное, но все еще действительное. Я в любом случае буду использовать библиотеку Стивенса. Кажется, он знает намного больше об этих вещах, чем я :-).
2. Я не могу рекомендовать больше о его блоге, каждая статья там — кусок золота. Его книга тоже должна быть хорошей, хотя у меня пока нет времени ее прочитать.
3. Просто побочное замечание: используйте более новую
AsyncEx.Coordination
библиотеку , если можете. Более стараяAsyncEx
библиотека скоро переключится на новую версию.