• 使用Lazy优雅的解决构造函数中的异步需求


    使用Lazy<>优雅的解决构造函数中的异步需求

    前世今生

    从netframework 4.0开始,C#开始支持延迟初始化,通过Lazy关键字,我们可以声明某个对象为仅仅当第一次使用的时候,再初始化,如果一直没有调用,那就不初始化,省去了一部分不必要的开销,提升了效率

    线程安全性

    默认情况下,该类的所有公共和受保护成员 Lazy 都是线程安全的,并且可以从多个线程并发使用。 可以使用类型构造函数的参数(可选)和每个实例删除这些线程安全保证

    说到天生具备的线程安全,就来一个以Lazy依托写的懒汉式泛型单例,如下

    public class Singleton<T>
        where T : class, new()
    {
        public static T Instance = new Lazy<T>(() => new T()).Value;
    }
    

    起因

    说了这么多的废话,现在回归正题,在使用QuartZ.Net的时候需要编写的一个管理各个Job的JobManager, 如下

    public interface IQuartzJobService
    {
        /// <summary>
        /// 添加Job
        /// </summary>
        void AddJob(IJobDetail jobDetail, ITrigger trigger);
        /// <summary>
        /// 暂停所有任务
        /// </summary>
        Task PauseAll();
        /// <summary>
        /// 恢复所有任务
        /// </summary>
        Task ResumeAll();
        /// <summary>
        /// 停止指定的任务
        /// </summary>
        Task PauseJob(string key);
        /// <summary>
        /// 恢复指定的任务
        /// </summary>
        Task ResumeJob(string key);
        /// <summary>
        /// 暂停指定的任务组
        /// </summary>
        Task PauseJobs(string group);
        /// <summary>
        /// 恢复指定的任务组
        /// </summary>
        Task ResumeJobs(string group);
        /// <summary>
        /// 停止调度器
        /// </summary>
        Task Shutdown();
    }
    

    那么问题来了, 现实这些接口都需要IScheduler的支持,从IOC中拿到的ISchedulerFactory的GetScheduler方法是一个异步方法,为了图个方便又下面几种

    private readonly ILogger<QuartzJobService> _logger;
    private readonly IScheduler _scheduler;
    
    public QuartzJobService(ILogger<QuartzJobService> logger, ISchedulerFactory factory)
    {
        _logger = logger;
        // 1
        //_scheduler = factory.GetScheduler().Result;
        // 2
        //Task.Run(async () => _scheduler = await factory.GetScheduler().ConfigureAwait(false));
    }
    

    也行吧, 反正使用是没有什么问题的,如果碰到这个方法耗时非常久或者需要拿到这个耗时方法的返回结果来进行其他部分成员字段创建,多少就又那么一些难办或是不优雅

    使用今天讲解的主角Lazy来办这个事,如下

    private readonly ILogger<QuartzJobService> _logger;
    private readonly Lazy<Task<IScheduler>> _scheduler;
    
    public QuartzJobService(ILogger<QuartzJobService> logger, ISchedulerFactory factory)
    {
        _logger = logger;
        _scheduler = new Lazy<Task<IScheduler>>(factory.GetScheduler());
        //_scheduler = new Lazy<Task<IScheduler>>(async () =>
        //{
        //    var scheduler = await factory.GetScheduler();
        //    return scheduler;
        //});
    }
    

    我调试的过程中是使用的下面带lambda的,为了方便验证它会调用多少次, 我通过以下代码运行

    builder.Services.SetupQuartz(options =>
    {
        var jobKey = JobKey.Create(nameof(SimpleJob));
        options.AddJob<SimpleJob>(jobKey);
        options.AddTrigger(configure =>
        {
            configure.ForJob(jobKey)
            .WithCronSchedule("0/3 * * * * ?")
            .StartNow();
        });
    
        jobKey = JobKey.Create(nameof(SimpleJob1));
        options.AddJob<SimpleJob1>(jobKey);
        options.AddTrigger(configure =>
        {
            configure.ForJob(jobKey)
            .WithCronSchedule("0/5 * * * * ?")
            .StartNow();
        });
    });
    
    var app = builder.Build();
    var quartz = app.Services.GetRequiredService<IQuartzJobService>();
    quartz.PauseJob(nameof(SimpleJob));
    quartz.ResumeJob(nameof(SimpleJob));
    quartz.PauseJob(nameof(SimpleJob1));
    quartz.ResumeJob(nameof(SimpleJob1));
    
    //......
    public async Task PauseJob(string key)
    {
        var scheduler = await _scheduler.Value;
        await scheduler.PauseJob(JobKey.Create(key));
    }
    
    public async Task ResumeJob(string key)
    {
        var scheduler = await _scheduler.Value;
        await scheduler.ResumeJob(JobKey.Create(key));
    }
    

    验证结果如所料那样, 第一次调用Pause时调用Lazy<>里面的lambda,然后剩下三次都不会再去调用Lazy<>里面的lambda了, 这个在一些特定的场合时非常省心的, 特别时不想再写一个其他的InitializeAsync类似的方法来给Constructor解围时,而且DI中用了类似InitializeAsync之类的辅助类异步初始化感觉是怪怪的,所以这个Lazy是很实用的, 突出一个按需使用

  • 相关阅读:
    MongoDB repair on Ubuntu
    java后台图形相关代码,weblogic报错
    weblogic配置达梦数据源
    详解JavaScript中的this
    web app指南之构建html5离线应用
    android中的跨进程通信的实现(一)——远程调用过程和aidl
    android应用开发全程实录出版
    android窗口管理框架解析
    BizTalk调用SAP系统RFC含多个参数以及DateTime类型参数
    plsql连接64位oracle在windows 764下连接设置方法
  • 原文地址:https://www.cnblogs.com/linxmouse/p/16420046.html
Copyright © 2020-2023  润新知