【问题标题】:async Lazy<T> getting results right awayasync Lazy<T> 立即获得结果
【发布时间】:2018-08-01 07:53:34
【问题描述】:

我有以下几点:

public class User 
{
        private readonly Lazy<Task<List<ReminderDb>>> _reminders;

        public SmsUserDb()
        {
            // Get _reminderReader from IoC

            _reminders = new Lazy<Task<List<ReminderDb>>>(async () => (List<ReminderDb>)await _reminderReader.Get(UserId));
        }

        public string UserId { get; set; }
        public Task<List<ReminderDb>> Reminders => _reminders.Value;
}

当我像这样实例化一个对象时:

    var n = new SmsUserDb {UserId = "123456"};
    var rems = await n.Reminders;

此代码有效,我看到 n.Reminders ="Waiting for activation" 直到我点击 await n.Reminders 行。

但是,当我像这样从缓存中查询此用户对象时:

        var n1 = await _userReader.GetUserFromCache("+17084556675"); // return SmsUserDb
        var n2 = await n1.Reminders;

当它点击 GetUserFromCache() 时,它会立即调用 _reminderReader.Get(UserId) 再次调用缓存以获取提醒。然后它只是超时。所以 Lazy 不起作用,很可能会导致死锁。

public async Task<SmsUserDb> GetUserFromCache(string phoneNumber)
{
    var hash = CachedObjectType.smsuser.ToString();
    var fieldKey = string.Format($"{CachedObjectType.smsuser.ToString()}:user-{phoneNumber}");
    var result = await _cacheUserService.GetHashedAsync(hash, fieldKey);
    return result;
}

    private async Task<List<ReminderDb>> GetRemindersFromCache(string userId)
    {
        var hash = CachedObjectType.smsreminder.ToString();
        var fieldKey = string.Format($"{CachedObjectType.smsreminder.ToString()}:user-{userId}");
        var result = await _cacheService.GetHashedAsync(hash, fieldKey);
        return result ?? new List<ReminderDb>();
    }

可能是什么问题?

【问题讨论】:

  • 那么GetUserFromCache() 是做什么的?
  • 简单地从缓存中获取用户(我已经添加了那个方法)。但我的意图是,在我执行 await user.Reminders; 的某个地方之前,不会调用 Reminders 属性。此外,如果我从 SmsUserDb 对象中删除 Reminder 属性它工作正常。好像是 Lazy 导致了问题。
  • 问题不清楚,代码不完整。这个 _reminderReader.Get(UserId) 到底是什么?
  • _reminderReader.Get(userId) 简单地调用这个 => GetRemindersFromCache()
  • 这在我的测试代码中一切正常。该错误必须与您缓存数据的方式有关。也许是序列化/反序列化?您需要发布一个完整的可编译示例,因为您实际发布的所有代码都可以正常工作。

标签: c# asp.net .net lazy-initialization


【解决方案1】:

这在我的测试代码中一切正常(如下所示)。因此,错误必须在您没有向我们展示的某些代码中。

这是一些有效的示例代码 - 它证明Lazy&lt;T&gt; 工作正常。因此,错误在您的代码中的其他地方。

您必须发布可编译的复制品,以便任何人帮助您。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Demo
{
    public class ReminderDb
    {
        public string Value;
    }

    public class ReminderReader
    {
        public async Task<List<ReminderDb>> Get(string userId)
        {
            Console.WriteLine("In Get() for " + userId);
            await Task.Delay(1000);
            Console.WriteLine("Returning from Get()");
            return new List<ReminderDb>{new ReminderDb{Value = userId}};
        }
    }

    public class Cache
    {
        public void Add(string key, SmsUserDb value)
        {
            _cache.Add(key, value);
        }

        public async Task<SmsUserDb> GetHashedAsync(string key)
        {
            await Task.Delay(1000);
            return _cache[key];
        }

        readonly Dictionary<string, SmsUserDb> _cache = new Dictionary<string, SmsUserDb>();
    }

    public class SmsUserDb
    {
        readonly Lazy<Task<List<ReminderDb>>> _reminders;
        readonly ReminderReader _reminderReader = new ReminderReader();

        public SmsUserDb()
        {
            _reminders = new Lazy<Task<List<ReminderDb>>>(async () => (List<ReminderDb>) await _reminderReader.Get(UserId));
        }

        public string                 UserId    { get; set; }
        public Task<List<ReminderDb>> Reminders => _reminders.Value;
    }

    static class Program
    {
        static async Task Main()
        {
            var db = new SmsUserDb(){UserId = "user ID"};
            var cache = new Cache();
            cache.Add("key", db);

            Console.WriteLine("Press RETURN to await cache.GetHashedAsync()");
            Console.ReadLine();
            var result = await cache.GetHashedAsync("key");

            Console.WriteLine("Press RETURN to await Reminders[0].Value");
            Console.ReadLine();
            Console.WriteLine((await result.Reminders)[0].Value);
        }
    }
}

【讨论】:

    【解决方案2】:

    发现问题。我是用同一个类写缓存的,也就是:

    public class User 
    {
            private readonly Lazy<Task<List<ReminderDb>>> _reminders;
    
            public SmsUserDb()
            {
                // Get _reminderReader from IoC
    
                _reminders = new Lazy<Task<List<ReminderDb>>>(async () => (List<ReminderDb>)await _reminderReader.Get(UserId));
            }
    
            public string UserId { get; set; }
            public Task<List<ReminderDb>> Reminders => _reminders.Value;
    }
    

    在使用不同的类进行写作(下)和阅读(上)后,一切都可以正常工作。谢谢

    public class CacheUser {
        public string UserId { get; set; }
        public List<ReminderDb> Reminders {get; set; }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-12
      • 2020-02-13
      相关资源
      最近更新 更多