状态机模式中的Task与对象池

Task

抽象带来Task

首先,假设我们有这么一段逻辑:收到一个参数,先校验格式是否正确,再提取相关的参数出来,执行我们的事务,然后构建结果并返回。伪代码如下:

/**
* 一个engine类
**/
public class Engine {
    public void init();
    public void cancel();
    public void restart();
    // 处理逻辑
    public void handleEvent(Param param) {
        validateParam(param);

        retrieveParam(param);

        handleTransaction(param);

        buildResult(param);

        response(param);
    }
}

在上面的handleEvent方法里面,处理逻辑与Engine并没有太多的联系,我们可以将这个逻辑抽离出来,或者说可以变得更抽象一点,如下:

/**
 * 一个engine类
 **/
public class Engine {
    public void init();
    public void cancel();
    public void restart();
    // 将处理逻辑抽象成Task类之后,Engine变得很简洁了
    public void handleEvent(Param param) {
        new Task().start(param);
    }
}


class Task{
    public void start(Param param){
        validateParam(param);

        retrieveParam(param);

        handleTransaction(param);

        buildResult(param);

        response(param);
    }
}

当然,如果engine被调用非常频繁,那么每次处理都新建一个Task类的话,会容易浪费内存,可以再优化一下性能,如下:

/**
 * 一个engine类
 **/
public class Engine {
    public void init();
    public void cancel();
    public void restart();
    // 减少新对象的创建可以将Task对象变成单例模式,或者将方法变成静态,这里取后者
    public void handleEvent(Param param) {
        Task.start(param);
    }
}

class Task{
    public static void start(Param param){
        // ......
    }
}

异步需要状态

如果上面的处理步骤有一个很耗时,例如handleTransaction方法需要10s才能返回,那么我们就需要将这个方法改造成异步的了,要不然就很影响engine的吞吐效率。这样,我们就需要一个状态标识符,用来标识handleTransaction方法是否执行完成,这个标识符可以放在engine里面,engine创建一个Map<Param,boolean>的成员变量,当handleTransaction方法执行完成产生回调,engine继续执行剩下的方法。

/**
 * 一个engine类
 **/
public class Engine {
    private Map<Param, Boolean> statusMap = new HashMap<Param, Boolean>();
    
    public void init();
    public void cancel();
    public void restart();
    /**
     * 处理逻辑
     **/
    public void handleEvent(Param param) {
        boolean isInitHandle = statusMap.getOrDefault(param, Boolean.FALSE);
        if (isInitHandle) {
            Task.handleParamBeforeTransaction(param);
            Task.handleTransaction(param);
        }else{
            Task.buildResultAndResponse(param);
        }
    }
}

class Task{
    public static void handleParamBeforeTransaction(Param param){
        validateParam(param);

        retrieveParam(param);
    }
    
    public static void handleTransaction(Param param){
        
    }

    public static void buildResultAndResponse(Param param) {
        buildResult(param);

        response(param);
    }
}

不过,这样就破坏了Engine类的抽象,Engine是管理者,但是却持有每次请求的状态,这样的管理类管的太细。比较好的抽象方式是将赋予Task状态,Engine直接管理Task。

/**
 * 一个engine类
 **/
public class Engine {
    private Map<Param, Task> taskMap = new HashMap<Param, Task>();

    public void init();
    public void cancel();
    public void restart();
    /**
     * 处理逻辑
     **/
    public void handleEvent(Param param) {
        Task task = taskMap.computeIfAbsent(param, newParam ->new Task());
        task.handle(param);
    }
    
    public void releaseTask(Param param){
        taskMap.remove(param);
    }
}

class Task{
    private boolean isInit ;
    private Engine engine;
    public Task(Engine engine) {
        this.engine = engine;
        isInit=false;
    }

    public void handle(Param param) {
        if (!isInit) {
            handleParamBeforeTransaction(param);
            handleTransaction(param);
        }else{
            buildResultAndResponse(param);
            engine.releaseTask(param);
        }
    }

    private void handleParamBeforeTransaction(Param param){
        validateParam(param);

        retrieveParam(param);
    }

    private void handleTransaction(Param param){

    }

    private void buildResultAndResponse(Param param) {
        buildResult(param);

        response(param);
    }
}

Task含有一个isInit的成员变量,可以根据这个状态来判断应该执行什么操作,实际上这就是状态机模式了。我们进行这般改造之后,Engine的吞吐量会提高很多,而且抽象程度比较高。
不过,每次处理Task都需要新建一个对象出来,又回到了刚开始的时候。一旦Engine的tps上去,不断创建、释放的Task对GC肯定有不小的影响。

对象池

不断创建的Task实例,如果整个处理逻辑的时间都比较短,那么都可以在YGC时回收掉内存,如果时间比较长,那肯定有相当部分的Task实例被不断地移到老年代,这样很显然会导致更长时间的FGC。异步要求保留状态,而有状态就要求有新实例,Task的创建不可避免,可以考虑将Task实例放到对象池里面回收利用。

/**
 * 一个engine类
 **/
public class Engine {
    private Map<Param, Task> taskMap = new HashMap<Param, Task>();

    public void init();

    public void cancel();

    public void restart();

    /**
     * 处理逻辑
     **/
    public void handleEvent(Param param) {
        Task task = taskMap.computeIfAbsent(param, newParam -> TaskPool.getTask());
        task.init(this);
        task.handle(param);
    }

    public void releaseTask(Param param) {
        Task task = taskMap.remove(param);
        TaskPool.releaseTask(task);
    }
}

/**
Task实例的对象池
*/
class TaskPool {
    private static Queue<Task> taskPool = new LinkedList<>();

    public static Task getTask() {
        Task task = taskPool.poll();
        if (task == null) {
            task = new Task();
        }
        return task;
    }

    public static void releaseTask(Task task) {
        if(task!=null) {
            task.reset();
            taskPool.add(task);
        }
    }
}

class Task {
    private boolean isInit;
    private Engine engine;
    // 由于Task放到对象池当中,需要提供一个init与reset方法,以回收利用
    public void init(Engine engine) {
        this.engine = engine;
        isInit = false;
    }

    public void reset() {
        this.engine = null;
        isInit = false;
    }

    public void handle(Param param) {
        if (!isInit) {
            handleParamBeforeTransaction(param);
            handleTransaction(param);
        } else {
            buildResultAndResponse(param);
            engine.releaseTask(param);
        }
    }

    private void handleParamBeforeTransaction(Param param) {
        validateParam(param);

        retrieveParam(param);
    }

    private void handleTransaction(Param param) {

    }

    private void buildResultAndResponse(Param param) {
        buildResult(param);

        response(param);
    }
}

由于Task实例从对象池(会放置到老年代里面)当中获取,这样就可以减少从新生代创建的内存浪费。这样在engine高tps的情况下,可以减少些gc,相当于从JVM的世界里面偷了点时间出来(这样想想还是有点刺激的)。

转载于:https://www.cnblogs.com/oreo/p/10629763.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
嵌入式软件架构状态机任务是一种在嵌入式系统常用的任务编程模型。状态机任务是基于状态机的概念设计的,通过对任务状态的切换和转移来实现任务调度和控制。 嵌入式系统通常存在多个任务需要执行,每个任务在不同的状态下执行不同的功能。状态机任务的设计主要包括状态定义、状态迁移条件和状态转移动作。 首先,需要明确定义每个任务可能的所有状态。状态可以是系统的工作状态、事件发生的状态或任务执行的状态。例如,一个温度控制系统可能有待机、工作和报警等不同的状态。 接下来,需要定义每个状态之间的迁移条件。迁移条件为状态转移提供了触发条件,只有当满足特定条件时,任务才能从当前状态迁移到下一个状态。可以通过检测输入信号、定时器到期、系统状态变化等方式来触发状态迁移。 最后,需要定义每个状态转移的动作。动作是在状态转变时执行的特定任务,可以是从外部设备接收数据、发送命令、更新状态变量等。通过定义适当的动作,可以实现任务在每个状态下的具体功能。 状态机任务的优势在于简化了任务的设计和实现。通过明确定义状态和状态转移条件,可以清晰地描述任务的行为和逻辑。同时,状态机任务也实现了任务的自动切换和调度,提高了系统的响应速度和效率。 总之,嵌入式软件架构状态机任务是一种基于状态机概念的任务编程模型,通过定义状态、迁移条件和动作来实现任务的调度和控制。它可以帮助开发人员简化任务的设计和实现,提高系统的响应速度和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值