大循环改造

有时候会看到在代码中存在一个大循环,整个过程需要执行很久,例如:

// 获取所有租户ID清单
List<string> list = GetAllTenantId();

// 用StringBuilder来存储所有租房的处理过程
StringBuilder sb = new ();

foreach(string tenantId in list) {

    // 在循环中一次处理一个租户
    string text = ProcessTenant(tenantId);
    sb.AppendLine(text);
}

// 给外界发送通知
SendNotify(sb.ToString());




推荐的实现方式

1,先定义消息类型

public class WorkArgs {
    public string TenantId {get; set;}
    public string 其它所需的参数 {get; set;}


    // 用于记录执行过程中产生的消息(此属性不是必需)
    public StringBuilder Messages;

    // 用于记录执行了多少次(此属性不是必需)
    public ValueCounter ExecCounter;
}

2,程序初始化时注册消息订阅者

private static readonly MemoryMesssageQueue<Product> s_syncMMQ 
                            = new MemoryMesssageQueue<Product>(MmqWorkMode.Sync);

MmqSubscriber.Start<WorkArgs, DemoMssageHandler>(new MmqSubscriberArgs {
    Queue = s_syncMMQ,
    SubscriberCount = LocalSettings.GetUInt("DemoMssageHandler_Subscriber_Count", 5)
});

3,用BackgroudTask来产生子任务消息

public class Task1 : BackgroundTask
{
    public override int? SleepSeconds => 3600;    // 假设1小时执行一次

    public override void Execute()
    {
        // 获取所有租户ID清单
        List<string> list = GetAllTenantId();

        // 用StringBuilder来存储所有租房的处理过程
        StringBuilder sb = new ();

        ValueCounter counter = new ();
        counter.Set(list.Count);

        foreach(string tenantId in list) {

            WorkArgs args = new WorkArgs{ 
                TenantId = tenantId,
                Messages = sb,
                ExecCounter = counter
            };
            s_syncMMQ.Write(args);
        }
    }
}

4,执行子任务逻辑-MessageHandler

public class DemoMssageHandler : BaseMessageHandler<WorkArgs>
{
    public override void ProcessMessage(PipelineContext<WorkArgs> context)
    {
        // 获取消息对象
        WorkArgs args = context.MessageData;
        
        string text = ProcessTenant(args);

        lock(args.Messages){
            args.Messages.AppendLine(text);
        }

        long count = args.ExecCounter.Decrement();

        if( count == 0 ){ // 所有子任务已全部执行结束
             SendNotify(sb.ToString());
        }
    }
}