/*******************************************************
*
* 作者:朱皖苏
* 创建日期: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; }
}
}