Правильный способ преобразования метода в асинхронный в C #?

Я пытаюсь преобразовать следующий метод (упрощенный пример) в асинхронный, поскольку вызов cacheMissResolver может быть дорогостоящим времени (поиск в базе данных, сетевой вызов):

// Synchronous version
public class ThingCache
{
    private static readonly object _lockObj;
    // ... other stuff

    public Thing Get(string key, Func<Thing> cacheMissResolver)
    {
        if (cache.Contains(key))
            return cache[key];

        Thing item;

        lock(_lockObj)
        {
            if (cache.Contains(key))
                return cache[key];

            item = cacheMissResolver();    
            cache.Add(key, item);
        }

        return item;
    }
}

В Интернете много материалов о потреблении асинхронных методов, но совет, который я нашел по их производству, кажется менее четким. Учитывая, что это является частью библиотеки, правильны ли мои попытки ниже?

// Asynchronous attempts
public class ThingCache
{
    private static readonly SemaphoreSlim _lockObj = new SemaphoreSlim(1);
    // ... other stuff

    // attempt #1
    public async Task<Thing> Get(string key, Func<Thing> cacheMissResolver)
    {
        if (cache.Contains(key))
            return await Task.FromResult(cache[key]);

        Thing item;

        await _lockObj.WaitAsync();

        try
        {
            if (cache.Contains(key))
                return await Task.FromResult(cache[key]);

            item = await Task.Run(cacheMissResolver).ConfigureAwait(false);
            _cache.Add(key, item);
        }
        finally
        {
            _lockObj.Release();
        }

        return item;
    }

    // attempt #2
    public async Task<Thing> Get(string key, Func<Task<Thing>> cacheMissResolver)
    {
        if (cache.Contains(key))
            return await Task.FromResult(cache[key]);

        Thing item;

        await _lockObj.WaitAsync();

        try
        {
            if (cache.Contains(key))
                return await Task.FromResult(cache[key]);

            item = await cacheMissResolver().ConfigureAwait(false);
            _cache.Add(key, item);
        }
        finally
        {
            _lockObj.Release();
        }

        return item;
    }
}

Является ли использование SemaphoreSlim правильным способом замены оператора блокировки в асинхронном методе? (Я не могу ждать в теле оператора блокировки.)

Должен ли я сделать аргумент cacheMissResolver типа Func<Task<Thing>> вместо? Хотя это накладывает бремя проверки того, что функция распознавателя является асинхронной для вызывающей стороны (добавление в Task.Run, я знаю, что оно будет выгружено в фоновый поток, если это занимает много времени).

Спасибо.

7 голосов | спросил rob 3 J0000006Europe/Moscow 2015, 23:07:42

0 ответов


Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132