代码之家  ›  专栏  ›  技术社区  ›  ShaneKm

Async Lazy<t>立即获得结果

  •  -1
  • ShaneKm  · 技术社区  · 6 年前

    我有以下几点:

    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”直到我点击waiting n.reminders行。

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

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

    当它点击getuserfromcache()时,它立即调用_reminderreader.get(userid),后者再次调用cache以获取提醒。然后就超时了。所以懒惰不起作用,很可能导致死锁。

    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>();
        }
    

    有什么问题?

    2 回复  |  直到 6 年前
        1
  •  1
  •   Matthew Watson    6 年前

    Lazy<T>

    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
  •  0
  •   ShaneKm    6 年前

    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; }
    }