LoopBox 用于包装循环的盒子

Posted zhuwansu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LoopBox 用于包装循环的盒子相关的知识,希望对你有一定的参考价值。

/*******************************************************
 * 
 * 作者:朱皖苏
 * 创建日期:20180608
 * 说明:此文件只包含一个类,具体内容见类型注释。
 * 版本号:1.0.0
 * 
 * 历史记录:
 * 创建文件 朱皖苏 20180608 16:06
 * 
*******************************************************/

using System;
using System.Diagnostics;
using System.Threading;

namespace Dben.CommonLib.LoopBox
{

    /// <summary>
    /// 封装了重复执行一段程序 n 次,它会额外输出每次处理耗时及计划完成时间。
    /// 继承此类以实现一个可配置的批处理数据程序。
    /// </summary>
    public abstract class LoopBox
    {
        /// <summary>
        /// 构造函数写入 <see cref="Context"/> 实例
        /// </summary>
        public LoopBox()
        {
            Context = InitContext();
        }

        /// <summary>
        /// 循环中的上下文对象
        /// </summary>
        protected ILoopContext Context { get; private set; }

        /// <summary>
        /// 循环执行任务。 box 的启动程序。
        /// </summary>
        /// <param name="loopBoxConfig"></param>
        public void Loop(LoopBoxConfig loopBoxConfig)
        {
            var log = $"处理计划:计划数据:{ loopBoxConfig.PlanTotal} 条,每次处理 {loopBoxConfig.LoopBatch} 条,共计处理 {loopBoxConfig.LoopCount}次";
            LogOutput(log);
            Context.Config = loopBoxConfig;
            var swItem = new Stopwatch();
            var swTotal = new Stopwatch();
            swTotal.Start();
            for (int i = 1; i <= loopBoxConfig.LoopCount; i++)
            {
                Context.Index = i;
                try
                {
                    swItem.Start();
                    Do();
                    swItem.Stop();
                    LogOutput($"第{i}/{loopBoxConfig.LoopCount}批执行完毕,执行耗时 {swItem.Elapsed.TotalSeconds} 秒,总耗时 {swTotal.Elapsed.TotalSeconds} 秒。预计剩余时间 {(loopBoxConfig.LoopCount - i == 0 ? 0 : swTotal.Elapsed.TotalSeconds / i * (loopBoxConfig.LoopCount - i))} 秒。 ");
                }
                catch (Exception e)
                {
                    LogOutput($"第{i}/{loopBoxConfig.LoopCount}批执行出现异常:{e.Message + e.StackTrace}");
                    throw e;
                }
                finally
                {
                    swItem.Reset();
                }
            }
            swTotal.Stop();
        }

        /// <summary>
        /// 初始化上下文对象,
        /// 需要提供一个简单的接口数据 <see cref="ILoopContext"/>/// 以确定执行 <see cref="Do"/> 的次数和输出执行的相关信息。
        /// 推荐使用默认 <see cref="DefaultLoopContext{T}"/>
        /// </summary>
        /// <returns></returns>
        protected abstract ILoopContext InitContext();

        /// <summary>
        /// 此函数为迭代中要执行的方法,
        /// <para>
        /// 相关的参数、结果的数据传递请使用自定义上下文或者继承<see cref="ILoopContext"/>,
        /// </para>
        /// 一般场景推荐使用默认的上下文对象<see cref="DefaultLoopContext{T}"/>
        /// </summary>
        protected abstract void Do();

        /// <summary>
        /// 此函数为 box 出口。实现此函数以及时响应程序执行过程和进度。
        /// </summary>
        /// <param name="log"></param>
        protected abstract void LogOutput(string log);
    }
}
/*******************************************************
 * 
 * 作者:朱皖苏
 * 创建日期:20180608
 * 说明:此文件只包含一个类,具体内容见类型注释。
 * 版本号:1.0.0
 * 
 * 历史记录:
 * 创建文件 朱皖苏 20180608 16:06
 * 
*******************************************************/

using System;
using System.Linq;

namespace Dben.CommonLib.LoopBox
{
    public class LoopBoxConfig
    {
        public LoopBoxConfig(long planTotal = 0, long loopBatch = 0, long loopCount = 0)
        {
            var items = new long[3] { planTotal, loopBatch, loopCount };

            if (items.Count(m => m < 1) >= 2)
            {
                throw new Exception("You can‘t have two or three attribute values that are less than zero at the same time.");
            }
            PlanTotal = planTotal;
            LoopBatch = loopBatch;
            LoopCount = loopCount;
        }

        private long loopCount;
        private long loopBatch;
        private long planTotal;
        public long LoopCount
        {
            get
            {
                if (loopCount < 1)
                {
                    loopCount = (long)Math.Ceiling((decimal)PlanTotal / LoopBatch);
                }
                return loopCount;
            }
            private set { loopCount = value; }
        }

        public long LoopBatch
        {
            get
            {
                if (loopBatch < 1)
                {
                    loopBatch = (long)Math.Ceiling((decimal)PlanTotal / LoopCount);
                }
                return loopBatch;
            }
            private set
            {
                loopBatch = value;
            }
        }

        public long PlanTotal
        {
            get
            {
                if (planTotal < 1)
                {
                    planTotal = LoopCount * LoopBatch;
                }
                return planTotal;
            }
            private set
            {
                planTotal = value;
            }
        }

    }
}
/*******************************************************
 * 
 * 作者:朱皖苏
 * 创建日期:20180608
 * 说明:此文件只包含一个类,具体内容见类型注释。
 * 版本号:1.0.0
 * 
 * 历史记录:
 * 创建文件 朱皖苏 20180608 16:06
 * 
*******************************************************/

namespace Dben.CommonLib.LoopBox
{
    public interface ILoopContext
    {
        LoopBoxConfig Config { get; set; }
        int Index { get; set; }
    }
}
/*******************************************************
 * 
 * 作者:朱皖苏
 * 创建日期:20180608
 * 说明:此文件只包含一个类,具体内容见类型注释。
 * 版本号:1.0.0
 * 
 * 历史记录:
 * 创建文件 朱皖苏 20180608 16:07
 * 
*******************************************************/

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

namespace Dben.CommonLib.LoopBox
{
    /// <summary>
    /// 默认的上下文对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public sealed class DefaultLoopContext<T> : ILoopContext
    {
        public T Tag { get; set; }
        public LoopBoxConfig Config { get; set; }
        public int Index { get; set; }
    }
}

 

以上是关于LoopBox 用于包装循环的盒子的主要内容,如果未能解决你的问题,请参考以下文章

常用python日期日志获取内容循环的代码片段

使用从循环内的代码片段中提取的函数避免代码冗余/计算开销

<code> vs <pre> vs <samp> 用于内联和块代码片段

单击时多次更改 Div 背景颜色(循环)

多边形包装盒材料选择——合力佳

如何组合绑定片段而不将它们包装在 XML 文字中