设计模式-状态机模式

news2024/11/16 8:57:10

参考

什么是状态机?
设计模式-状态机模式

什么是状态机(有限状态自动机)

可以把状态机比作方程式, 你输入当前信息, 就能得到下一个信息
在这里插入图片描述
举个例子, 按钮门有两个状态, 关闭状态和打开状态, 如果按下开门按钮, 门的状态就从关闭到打开
在这里插入图片描述
状态机就是接受门当前状态和发生的事件, 输出门的下一个状态

状态机四大概念

1. 状态(State):

一个状态机至少包含两个状态, 门, 就有两个状态, 一个打开状态, 一个关闭状态

2. 事件(Event):

一个行为, 一个操作的触发条件, 门, 按下开门按钮, 这是一个事件, 一个事件对应一个动作

3. 动作(Action):

事件发生后要执行的动作, 门被按下开门按钮, 这个事件发生后, 门会执行动作, 门打开了

4. 变换(Transition):

表示一个状态变成另一个状态的过程, 在执行完action后, 门的状态也就从关闭状态到打开

类图

一个事件绑定一个动作
一个状态绑定多个事件
Machine 需要初始化添加所有状态, 事件所对应的动作, 状态所对应事件
在这里插入图片描述

Machine优化
在这里插入图片描述

实战

模拟玩家进入大厅, 选择房间进行游戏, 再退出房间, 退出游戏的操作
在这里插入图片描述
看玩家空闲状态->在游戏大厅那条连线, 初始状态是 空闲, 事件是 按下进入游戏按钮, 行动是 玩家进入游戏, 变换是 状态从空闲变为在游戏大厅

玩家状态分析

玩家状态: 空闲, 在游戏大厅, 在房间201, 在房间202
在这里插入图片描述

玩家事件分析

在这里插入图片描述

玩家Action

一个事件绑定一个Action
UserMichine中事件绑定的Action

事件动作
PressEnterGameBtnEnterGameAction
PressLeaveGameBtnLeaveGameAction
PressEnterGameRoom201BtnEnterGameRoom201Action
PressEnterGameRoom202BtnEnterGameRoom202Action
PressLeaveGameRoom201BtnLeaveGameRoom201Action
PressLeaveGameRoom202BtnLeaveGameRoom202Action

代码

在这里插入图片描述
Action.h

#ifndef _ACTION_H_
#define _ACTION_H_

#include <memory>
#include <iostream>
#include "Event.h"
#include "State.h"

class Action{
public:
    Action(int curState, int nextState): m_curState(curState), m_nextState(nextState)
    {
    }

    virtual std::shared_ptr<State> Execute(std::shared_ptr<State> state, std::shared_ptr<Event> event)
    {
        std::shared_ptr<State> nextState = std::make_shared<UserState>(m_nextState);
        std::cout << event->GetEventActionName() << ", 玩家状态从 " << state->GetString() << " 到 " << nextState->GetString() << std::endl;
        return nextState;
    }
public:
    int m_curState;
    int m_nextState;
};

// 对应 PressEnterGameBtn事件
class EnterGameAction: public Action{
public:
    EnterGameAction(int curState, int nextState): Action(curState, nextState){}
    virtual std::shared_ptr<State> Execute(std::shared_ptr<State> state, std::shared_ptr<Event> event)
    {   
        // EnterGameAction 特别操作 TODO
        std::shared_ptr<State> nextState = std::make_shared<UserState>(m_nextState);
        auto userEvent = std::static_pointer_cast<UserEvent>(event);
        std::cout << userEvent->m_userName << " " << event->GetEventActionName() << ", 玩家状态从 " << state->GetString() << " 到 " << nextState->GetString() << std::endl;
        return nextState;
    }
};

// 对应 PressLeaveGameBtn事件
class LeaveGameAction: public Action{
public:
    LeaveGameAction(int curState, int nextState): Action(curState, nextState){}
    virtual std::shared_ptr<State> Execute(std::shared_ptr<State> state, std::shared_ptr<Event> event)
    {   
        // LeaveGameAction 特别操作 TODO
        std::shared_ptr<State> nextState = std::make_shared<UserState>(m_nextState);
        auto userEvent = std::static_pointer_cast<UserEvent>(event);
        std::cout << userEvent->m_userName << " " << event->GetEventActionName() << ", 玩家状态从 " << state->GetString() << " 到 " << nextState->GetString() << std::endl;
        return nextState;
    }
};

// 对应 PressEnterGameRoom201Btn事件
class EnterGameRoom201Action: public Action{
public:
    EnterGameRoom201Action(int curState, int nextState): Action(curState, nextState){}
    virtual std::shared_ptr<State> Execute(std::shared_ptr<State> state, std::shared_ptr<Event> event)
    {   
        // EnterGameRoom201Action 特别操作 TODO
        std::shared_ptr<State> nextState = std::make_shared<UserState>(m_nextState);
        auto userEvent = std::static_pointer_cast<UserEvent>(event);
        std::cout << userEvent->m_userName << " " << event->GetEventActionName() << ", 玩家状态从 " << state->GetString() << " 到 " << nextState->GetString() << std::endl;
        return nextState;
    }
};

// 对应 PressEnterGameRoom202Btn事件
class EnterGameRoom202Action: public Action{ //
public:
    EnterGameRoom202Action(int curState, int nextState): Action(curState, nextState){}
    virtual std::shared_ptr<State> Execute(std::shared_ptr<State> state, std::shared_ptr<Event> event)
    {   
        // EnterGameRoom202Action 特别操作 TODO
        std::shared_ptr<State> nextState = std::make_shared<UserState>(m_nextState);
        auto userEvent = std::static_pointer_cast<UserEvent>(event);
        std::cout << userEvent->m_userName << " " << event->GetEventActionName() << ", 玩家状态从 " << state->GetString() << " 到 " << nextState->GetString() << std::endl;
        return nextState;
    }
};

// 对应 PressLeaveGameRoom201Btn事件
class LeaveGameRoom201Action: public Action{
public:
    LeaveGameRoom201Action(int curState, int nextState): Action(curState, nextState){}
    virtual std::shared_ptr<State> Execute(std::shared_ptr<State> state, std::shared_ptr<Event> event)
    {   
        // LeaveGameRoom201Action 特别操作 TODO
        std::shared_ptr<State> nextState = std::make_shared<UserState>(m_nextState);
        auto userEvent = std::static_pointer_cast<UserEvent>(event);
        std::cout << userEvent->m_userName << " " << event->GetEventActionName() << ", 玩家状态从 " << state->GetString() << " 到 " << nextState->GetString() << std::endl;
        return nextState;
    }
};

// 对应 PressLeaveGameRoom202Btn事件
class LeaveGameRoom202Action: public Action{
public:
    LeaveGameRoom202Action(int curState, int nextState): Action(curState, nextState){}
    virtual std::shared_ptr<State> Execute(std::shared_ptr<State> state, std::shared_ptr<Event> event)
    {   
        // LeaveGameRoom202Action 特别操作 TODO
        std::shared_ptr<State> nextState = std::make_shared<UserState>(m_nextState);
        auto userEvent = std::static_pointer_cast<UserEvent>(event);
        std::cout << userEvent->m_userName << " " << event->GetEventActionName() << ", 玩家状态从 " << state->GetString() << " 到 " << nextState->GetString() << std::endl;
        return nextState;
    }
};

#endif

Event.h

#ifndef _EVENT_H_
#define _EVENT_H_

#include <string>
#include "SharedDef.h"

class Event{
public:
    Event(int eventId):m_eventId(eventId){}
    virtual std::string GetEventActionName(){
        return "";
    }
public:
    int m_eventId;
};

class UserEvent: public Event{
public:
    UserEvent(int eventId, std::string userName="玩家A"):Event(eventId),m_userName(userName){}
    virtual std::string GetEventActionName(){
        switch(m_eventId)
        {
            case PressEnterGameBtn:
                return "进入游戏";
            case PressLeaveGameBtn:
                return "离开游戏";
            case PressEnterGameRoom201Btn:
                return "进入201房间";
            case PressEnterGameRoom202Btn:
                return "进入202房间";
            case PressLeaveGameRoom201Btn:
                return "退出201房间";
            case PressLeaveGameRoom202Btn:
                return "退出202房间";
        }
    }
public:
    std::string m_userName;
};

#endif

SharedDef.h

#ifndef _SHARED_DEF_H
#define _SHARED_DEF_H

enum UserStateEnum {
    Idle,           // 空闲
    InGameHall,     // 在游戏大厅
    InRoom201,      // 在房间201
    InRoom202       // 在房间202
};

enum EventEnum {
    PressEnterGameBtn,              // 按下进入游戏按钮事件
    PressLeaveGameBtn,              // 按下离开游戏按钮事件
    PressEnterGameRoom201Btn,       // 按下进入201房间按钮事件
    PressEnterGameRoom202Btn,       // 按下进入202房间按钮事件
    PressLeaveGameRoom201Btn,       // 按下退出201房间按钮事件
    PressLeaveGameRoom202Btn        // 按下退出202房间按钮事件
};

#endif

State.h

#ifndef _STATE_H_
#define _STATE_H_

#include <string>
#include "SharedDef.h"

class State{
public:
    State(int stateId):m_stateId(stateId){}
    virtual std::string GetString(){
        return "";
    }
public:
    int m_stateId;
};

class UserState:public State{
public:
    UserState(int stateId):State(stateId){}
    virtual std::string GetString()
    {
        switch(m_stateId)
        {
            case Idle:
                return "空闲";
            case InGameHall:
                return "在游戏大厅";
            case InRoom201:
                return "在房间201";
            case InRoom202:
                return "在房间202";
        }

        return "无状态";
    }
};

#endif

UserMachine.h

#ifndef _USER_MACHINE_H_
#define _USER_MACHINE_H_

#include <unordered_map>
#include <memory>
#include "Event.h"
#include "State.h"
#include "Action.h"

typedef std::unordered_map<int, std::shared_ptr<Action>> EventAction;

class UserMachine
{
public:
    void Init();
    std::shared_ptr<State> Execute(int state, std::shared_ptr<Event> event);
    std::shared_ptr<State> Execute(std::shared_ptr<State> state, std::shared_ptr<Event> event);
public:
    std::unordered_map<int, std::unordered_map<int, std::shared_ptr<Action>>> m_stateEventsMap;        // <状态id,<事件id, Action>> 
};

#endif

UserMachine.cpp

#include <vector>
#include "UserMachine.h"

// 初始化, 事件绑定动作, 状态保定事件
void UserMachine::Init()
{
    m_stateEventsMap.clear();
    
    std::vector<std::shared_ptr<State>> states; states.clear();

    std::shared_ptr<State> idleState = std::make_shared<UserState>(Idle);
    std::shared_ptr<State> inGameHallState = std::make_shared<UserState>(InGameHall);
    std::shared_ptr<State> inRoom201State = std::make_shared<UserState>(InRoom201);
    std::shared_ptr<State> inRoom202State = std::make_shared<UserState>(InRoom202);

    states.push_back(idleState);
    states.push_back(inGameHallState);
    states.push_back(inRoom201State);
    states.push_back(inRoom202State);

    for(int i = 0; i < states.size(); i++)
    {
        EventAction eventActionMap; eventActionMap.clear();
        m_stateEventsMap.insert(std::make_pair(states[i]->m_stateId, eventActionMap));
    }
    
    // 空闲 -----按下进入游戏按钮-------> 游戏大厅
    std::shared_ptr<Action> idle_InGameHall_Action = std::make_shared<EnterGameAction>(Idle, InGameHall);
    m_stateEventsMap[idleState->m_stateId].insert(std::make_pair(PressEnterGameBtn, idle_InGameHall_Action));
    
    // 游戏大厅 -----按下退出游戏按钮-------> 休闲
    std::shared_ptr<Action> inGamehall_Idle_Action = std::make_shared<LeaveGameAction>(InGameHall, Idle);
    m_stateEventsMap[inGameHallState->m_stateId].insert(std::make_pair(PressLeaveGameBtn, inGamehall_Idle_Action));
    
    // 游戏大厅 -----按下进入201游戏按钮-------> 在房间201
    std::shared_ptr<Action> inGamehall_InRoom201_Action = std::make_shared<EnterGameRoom201Action>(InGameHall, InRoom201);
    m_stateEventsMap[inGameHallState->m_stateId].insert(std::make_pair(PressEnterGameRoom201Btn, inGamehall_InRoom201_Action));

    // 在房间201 -----按下退出201游戏按钮-------> 游戏大厅
    std::shared_ptr<Action> inRoom201_InGamehall_Action = std::make_shared<LeaveGameRoom201Action>(InRoom201, InGameHall);
    m_stateEventsMap[inRoom201State->m_stateId].insert(std::make_pair(PressLeaveGameRoom201Btn, inRoom201_InGamehall_Action));

     // 游戏大厅 -----按下进入202游戏按钮-------> 在房间202
    std::shared_ptr<Action> inGamehall_InRoom202_Action = std::make_shared<EnterGameRoom202Action>(InGameHall, InRoom202);
    m_stateEventsMap[inGameHallState->m_stateId].insert(std::make_pair(PressEnterGameRoom202Btn, inGamehall_InRoom202_Action));

    // 在房间202 -----按下退出202游戏按钮-------> 游戏大厅
    std::shared_ptr<Action> inRoom202_InGamehall_Action = std::make_shared<LeaveGameRoom202Action>(InRoom202, InGameHall);
    m_stateEventsMap[inRoom202State->m_stateId].insert(std::make_pair(PressLeaveGameRoom202Btn, inRoom202_InGamehall_Action));
}

std::shared_ptr<State> UserMachine::Execute(int state, std::shared_ptr<Event> event)
{
    if(m_stateEventsMap.count(state) == 0)
    {
        std::cout << "状态未注册" << std::endl; 
        return NULL;
    }

    EventAction ea = m_stateEventsMap[state];

    if(ea.count(event->m_eventId) == 0) 
    {
        std::cout << "未注册事件" << std::endl;
        return NULL;
    }

    std::shared_ptr<State> curState = std::make_shared<UserState>(state);

    return ea[event->m_eventId]->Execute(curState, event);
}

std::shared_ptr<State> UserMachine::Execute(std::shared_ptr<State> state, std::shared_ptr<Event> event)
{
    if(m_stateEventsMap.count(state->m_stateId) == 0)
    {
        std::cout << "状态未注册" << std::endl; 
        return NULL;
    }

    EventAction ea = m_stateEventsMap[state->m_stateId];

    if(ea.count(event->m_eventId) == 0) 
    {
        std::cout << "未注册事件" << std::endl;
        return NULL;
    }

    return ea[event->m_eventId]->Execute(state, event);
}

CMakeList.txt

cmake_minimum_required(VERSION 3.15)

project(main)

include_directories(./)

aux_source_directory(./ main_source)
aux_source_directory(./States states_source)

add_executable(main ${main_source} ${states_source})

main.cpp

#include <iostream>
#include <memory>
#include <string>
#include "States/SharedDef.h"
#include "States/Event.h"
#include "States/UserMachine.h"

int main()
{
    std::cout << "Hello World" << std::endl;

    std::shared_ptr<UserMachine> userMachine = std::make_shared<UserMachine>();
    userMachine->Init();
    // 预想 玩家空闲 + 按下进入游戏按钮 -> 玩家在游戏大厅
    auto nextState = userMachine->Execute(Idle, std::make_shared<UserEvent>(PressEnterGameBtn));
    // 预想 玩家空闲 + 按下进入房间201按钮 -> 玩家在房间201
    nextState = userMachine->Execute(nextState->m_stateId, std::make_shared<UserEvent>(PressEnterGameRoom201Btn));
    // 预想 玩家在房间 + 按下退出游戏按钮 -> X
    nextState = userMachine->Execute(nextState->m_stateId, std::make_shared<UserEvent>(PressLeaveGameBtn));

    getchar();
    return 0;
}

在这里插入图片描述

增加难度 添加房间状态

房间在有人的时候会打印有人, 没人的时候打印没人
要注意, 这里有两个房间, 也就是分别要保存这两个房间的状态, 但只需要一个Machine, Machine只是个数学公式, 两个房间的状态变化都是一样的
在这里插入图片描述
相比玩家的单纯的状态转移, 房间的状态转移增加了 转移条件 condistion
在这里插入图片描述

类图的修改

在之前的基础上把Transition从Action中提取出来
再增加一个Context类, 给转移条件传输必要的数据, 玩家人数是当前条件的必要项
在这里插入图片描述

房间状态分析

房间两种状态变化: 有人, 没人
在这里插入图片描述
注意不要和玩家状态的值重复了, 状态都是唯一的

房间事件分析

房间的人数变化, 状态变化, 跟玩家进出房间密切相关, 可以复用这些事件
在这里插入图片描述

房间Action

在这里插入图片描述

代码

抽象Machine
在这里插入图片描述
RoomMachine.h
重点: CheckUserCountM0 和 CheckUserCountL0 是Context自定义限制条件函数

#include <vector>
#include <functional>
#include "RoomMachine.h"
#include "../Context.h"
#include "../Action.h"

// 初始化, 事件绑定动作, 状态保定事件
void RoomMachine::Init()
{
    m_stateEventsMap.clear();
    
    std::vector<std::shared_ptr<State>> states; states.clear();

    std::shared_ptr<State> emptyState = std::make_shared<UserState>(Empty);
    std::shared_ptr<State> hasUserState = std::make_shared<UserState>(HasUser);

    states.push_back(emptyState);
    states.push_back(hasUserState);

    for(int i = 0; i < states.size(); i++)
    {
        EventAction eventActionMap; eventActionMap.clear();
        m_stateEventsMap.insert(std::make_pair(states[i]->m_stateId, eventActionMap));
    }
    

    std::function<bool(std::shared_ptr<Context>)> checkUserCountM0Func = std::bind(&RoomMachine::CheckUserCountM0, this, std::placeholders::_1);
    std::function<bool(std::shared_ptr<Context>)> checkUserCountL0Func = std::bind(&RoomMachine::CheckUserCountL0, this, std::placeholders::_1);
    
    std::shared_ptr<Action> hasUser_Empty_Action = std::make_shared<Room_LeaveGameRoomAction>(HasUser, Empty, checkUserCountL0Func);
    std::shared_ptr<Action> empty_HasUser_Action = std::make_shared<Room_EnterGameRoomAction>(Empty, HasUser, checkUserCountM0Func);

    // 没人状态 -----按下进入游戏房间按钮 + 判断人数 -------> 有人状态
    m_stateEventsMap[emptyState->m_stateId].insert(std::make_pair(PressEnterGameRoom201Btn, empty_HasUser_Action));
    m_stateEventsMap[emptyState->m_stateId].insert(std::make_pair(PressEnterGameRoom202Btn, empty_HasUser_Action));

    // 没人状态 -----按下退出游戏房间按钮 + 判断人数 -------> 无人状态
    m_stateEventsMap[emptyState->m_stateId].insert(std::make_pair(PressLeaveGameRoom201Btn, empty_HasUser_Action));
    m_stateEventsMap[emptyState->m_stateId].insert(std::make_pair(PressLeaveGameRoom202Btn, empty_HasUser_Action));

    // 有人状态 -----按下进入游戏房间按钮 + 判断人数 -------> 有人状态
    m_stateEventsMap[hasUserState->m_stateId].insert(std::make_pair(PressEnterGameRoom201Btn, hasUser_Empty_Action));
    m_stateEventsMap[hasUserState->m_stateId].insert(std::make_pair(PressEnterGameRoom202Btn, hasUser_Empty_Action));

    // 有人状态 -----按下退出游戏房间按钮 + 判断人数 -------> 无人状态
    m_stateEventsMap[hasUserState->m_stateId].insert(std::make_pair(PressLeaveGameRoom201Btn, hasUser_Empty_Action));
    m_stateEventsMap[hasUserState->m_stateId].insert(std::make_pair(PressLeaveGameRoom202Btn, hasUser_Empty_Action));
}

bool RoomMachine::CheckUserCountM0(std::shared_ptr<Context> context)
{
    if(context->m_userCount >= 0){
        return true;
    }
    return false;
}

bool RoomMachine::CheckUserCountL0(std::shared_ptr<Context> context)
{
    if(context->m_userCount <= 0){
        return true;
    }
    return false;
}

Action.h
原本简写的动作变化, int curState和int nextState, 集成到Transition, Transition同时保存了自定义限制函数
在这里插入图片描述
在这里插入图片描述
这是自定义限制函数在action 使用, 如果不满足条件, 返回自己本身的状态, 否则就是下一个状态
在这里插入图片描述
main.cpp 运行后, 符合预期

#include <iostream>
#include <memory>
#include <string>
#include "States/SharedDef.h"
#include "States/Event.h"
#include "States/Machine/UserMachine.h"
#include "States/Machine/RoomMachine.h"

int main()
{
    std::cout << "Hello World" << std::endl;

    std::shared_ptr<UserMachine> userMachine = std::make_shared<UserMachine>();
    std::shared_ptr<RoomMachine> roomMachine = std::make_shared<RoomMachine>();
    // 0 为 201, 1 为 202
    // 初始化玩家数量为0
    std::shared_ptr<Context> context[2];
    // 两间房间的状态
    std::shared_ptr<State> roomState[2];
    for(int i = 0; i < 2; i++)
    {
        context[i] = std::make_shared<Context>(0);
        roomState[i] = std::make_shared<RoomState>(Empty);
    }

    userMachine->Init();
    roomMachine->Init();

    // 预想 玩家A 空闲 + 按下进入游戏按钮 -> 玩家B 在游戏大厅
    auto nextState = userMachine->Execute(Idle, std::make_shared<UserEvent>(PressEnterGameBtn));
    // 预想 玩家B 空闲 + 按下进入游戏按钮 -> 玩家B 在游戏大厅
    auto nextState2 = userMachine->Execute(Idle, std::make_shared<UserEvent>(PressEnterGameBtn, "玩家B"));

    // 预想 玩家A 空闲 + 按下进入房间201按钮 -> 玩家A 在房间201
    nextState = userMachine->Execute(nextState->m_stateId, std::make_shared<UserEvent>(PressEnterGameRoom201Btn));
    if(nextState != NULL)
    {
        // 预想 房间201 空闲 + 按下进入房间201按钮 + context判断数据 -> 房间201 有人
        context[0]->m_userCount ++;
        roomState[0] = roomMachine->Execute(roomState[0], std::make_shared<RoomEvent>(PressEnterGameRoom201Btn), context[0]);
    }

    // 预想 玩家B空闲 + 按下进入房间201按钮 -> 玩家B 在房间201
    nextState2 = userMachine->Execute(nextState2->m_stateId, std::make_shared<UserEvent>(PressEnterGameRoom201Btn, "玩家B"));
    if(nextState2 != NULL)
    {
        // 预想 房间201 有人 + 按下进入房间201按钮 + context判断数据 -> 房间201 有人
        context[0]->m_userCount ++;
        roomState[0] = roomMachine->Execute(roomState[0], std::make_shared<RoomEvent>(PressEnterGameRoom201Btn), context[0]);
    }
    
    // 预想 玩家B 在房间201 + 按下离开房间201按钮 -> 玩家B 空闲
    nextState2 = userMachine->Execute(nextState2->m_stateId, std::make_shared<UserEvent>(PressLeaveGameRoom201Btn, "玩家B"));
    if(nextState2 != NULL)
    {
        // 预想 房间201 有人 + 按下推出房间201按钮 + context判断数据 -> 房间201 有人
        context[0]->m_userCount --;
        roomState[0] = roomMachine->Execute(roomState[0], std::make_shared<RoomEvent>(PressLeaveGameRoom201Btn), context[0]);
    }

    // 预想 玩家A 在房间201 + 按下离开房间201按钮 -> 玩家A 空闲
    nextState = userMachine->Execute(nextState->m_stateId, std::make_shared<UserEvent>(PressLeaveGameRoom201Btn));
    if(nextState != NULL)
    {
        // 预想 房间201 有人 + 按下离开房间201按钮 + context判断数据 -> 房间201 没人
        context[0]->m_userCount --;
        roomState[0] = roomMachine->Execute(roomState[0], std::make_shared<RoomEvent>(PressLeaveGameRoom201Btn), context[0]);
    }
    
    // 预想 玩家A 在房间201 + 按下退出游戏按钮 -> 未注册
    nextState = userMachine->Execute(InRoom201, std::make_shared<UserEvent>(PressLeaveGameBtn));
   
    getchar();
    return 0;
}

在这里插入图片描述

完整代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/354206.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

极兔一面:10亿级ES海量搜索狂飙10倍,该怎么办?

背景说明&#xff1a; ES高性能全文索引&#xff0c;如果不会用&#xff0c;或者没有用过&#xff0c;在面试中&#xff0c;会非常吃亏。 所以ES的实操和底层原理&#xff0c;大家要好好准备。 另外&#xff0c;ES调优是一个非常、非常核心的面试知识点&#xff0c;大家要非…

就业大山之下的网络安全:安逸的安服仔

从去年开始&#xff0c;各个互联网大厂就接二连三的放出了裁员消息&#xff0c;整个互联网行业好像都处于寒冬状态。微博、小米、滴滴、知乎、拼多多等在内的一大批互联网知名企业&#xff0c;也相继传出“人员优化”的消息。 除了国内市场的萧条&#xff0c;国外市场也是不容…

kubernetes教程 --Pod调度

Pod调度 在默认情况下&#xff0c;一个Pod在哪个Node节点上运行&#xff0c;是由Scheduler组件采用相应的算法计算出来的&#xff0c;这个过程是不受人工控制的。但是在实际使用中&#xff0c;这并不满足的需求&#xff0c;因为很多情况下&#xff0c;我们想控制某些Pod到达某…

springboot simple (13) springboot Elasticsearch(Elasticsearch8.5.1)

这里首先简单的介绍了Elasticsearch&#xff0c;然后实现了springboot集成Elasticsearch。 版本&#xff1a; Elasticsearch&#xff1a;v8.5.1 Kibana&#xff1a;v8.5.1 springboot集成elasticsearch有两种方式。 1&#xff09;rest客户端RestHingLevelClient&#xff1b; …

2.2 BeautifulSoup 装载HTML文档

HTML文档结点的查找工具很多&#xff0c;其中 BeautifulSoup 是功能强大且十分流行的查找工具之一。1. BeautifulSoup 的安装安装&#xff1a;pip install bs4导包&#xff1a;from bs4 import BeautifulSoup2. BeautifulSoup 装载HTML文档如果 doc 是一个 HTML 文档&#xff0…

fast planner总结

一、前端 kinodynamic A*算法动力学路径搜索 1.1 路径搜索的主要函数为kinodynamicAstar类的search函数 int KinodynamicAstar::search(Eigen::Vector3d start_pt, Eigen::Vector3d start_v, Eigen::Vector3d start_a,Eigen::Vector3d end_pt, Eigen::Vector3d end_v, bool ini…

DPDK — Userspace PMD 源码分析

目录 文章目录目录PMD driver 通过 IGB_UIO 与 UIO 进行交互注册一个 UIO 设备PMD 的应用层实现PMD 同样支持中断处理方式PMD driver 通过 IGB_UIO 与 UIO 进行交互 IGB_UIO 内核模块的另一个主要功能就是让用于态的 PMD 网卡驱动程序得以与 UIO 进行交互。对于 PMD 的实现来说…

松下PLC通过fpwin上传写入MRTC模块方法

目录 PLC程序上传方法 加密模块使用 PLC程序上传方法 手动将PLC模式设置为prog模式查看PLC是否设置为禁止上传查询指示灯是否变蓝&#xff0c;变蓝则需要将PLC禁止上传功能取消。 3.当上述动作操作完成后&#xff0c;将PLC程序导入到PLC中。为了配合加密程序使用&#xff0c;…

进程通信方式

无名管道( pipe )&#xff1a; 管道是一种半双工的通信方式&#xff0c;数据只能单向流动&#xff0c;而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。高级管道&#xff08;popen&#xff09;&#xff1a; 将另一个程序当做一个新的进程在当前程序进…

主成分分析(PCA)原理详解

1. 相关背景 在许多领域的研究与应用中&#xff0c;通常需要对含有多个变量的数据进行观测&#xff0c;收集大量数据后进行分析寻找规律。多变量大数据集无疑会为研究和应用提供丰富的信息&#xff0c;但是也在一定程度上增加了数据采集的工作量。更重要的是在很多情形下&…

Windows server——部署web服务

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 本章重点 一.web讲解 1.WWW概述 &#xff08;1&#xff09;WWW服务概述 &…

Linux应用编程下连接本地数据库进行增删改查系列操作

文章目录前言一、常用SQL操作语句二、相关函数解析三、连接本地数据库四、编译运行五、程序源码前言 本篇为C语言应用编程下连接Linux本地数据库进行增删改查系列操作。 在此之前&#xff0c;首先当然是你需要具备一定的数据库基础&#xff0c;所以下面我先列出部分常用的SQL…

如何利用文件上传漏洞-以及如何修复它们

目录什么是文件上传漏洞&#xff1f;文件上传请求如何工作为什么文件上传漏洞是个问题&#xff1f;漏洞 #1&#xff1a;通过文件内容远程代码执行&#xff08;Web Shell 上传&#xff09;绕过黑名单保护案例 1&#xff1a;案例 2&#xff1a;案例 3&#xff1a;案例 4&#xff…

【Spark分布式内存计算框架——Spark SQL】10. External DataSource(上)数据源与格式

第六章 External DataSource 在SparkSQL模块&#xff0c;提供一套完成API接口&#xff0c;用于方便读写外部数据源的的数据&#xff08;从Spark 1.4版本提供&#xff09;&#xff0c;框架本身内置外部数据源&#xff1a; 在Spark 2.4版本中添加支持Image Source&#xff08;图…

音频信号处理笔记(一)

相关课程&#xff1a;【音频信号处理及深度学习教程】 文章目录01 信号的时域分析1.1 分帧1.1.1 幅值包络1.1.2 均方根能量0 信号的叠加&#xff1a;https://teropa.info/harmonics-explorer/ 一个复杂信号分解成若干简单信号分量之和。不同个频率信号的叠加: 由于和差化积&a…

【Mysql基础 —— SQL语句(一)】

文章目录概述使用启动/停止mysql服务连接mysql客户端数据模型SQLSQL语句分类DDL数据库操作表操作查询创建数据类型修改删除DML添加数据修改数据删除数据DQL基础查询条件查询聚合函数分组查询排序查询分页查询执行顺序DCL管理用户权限控制概述 数据库&#xff08;Database&#…

如何评价一个新技术——以 ChatGPT 为例

开源社KAIYUANSHE近期微信公众号订阅功能做调整啦&#xff01;没有被星标的账号在信息流里可能不显示大图了&#xff01;快星标⭐我们&#xff0c;就可以及时看到发布的文章啦&#xff01;STEP01 点击右上角标志STEP02 点击【设为星标】缘起2015 年的时候&#xff0c;我写过一篇…

DaVinci 偏好设置:用户 - UI 设置

偏好设置 - 用户/ UI 设置Preferences - User/ UI Settings工作区选项Workspace Options语言Language指定 DaVinci Resolve 软件界面所使用的语言。目前支持英语、简体中文、日语、西班牙语、葡萄牙语、法语、俄语、泰语和越南语等等。启动时重新加载上一个工作项目Reload last…

Python 连接数据源与邮件功能(九)

文章目录一、概述二、Python 连接数据源1&#xff09;Python MySQL 基础操作1、部署MySQL2、MySQL Connector 库【1】安装 mysql-connector-python 库【2】连接 MySQL【3】增加数据【4】查询数据【5】更新数据【6】删除数据2、PyMySQL 库【1】安装 PyMySQL 库【2】连接 MySQL【…

2023年数学建模美赛D题(Prioritizing the UN Sustainability Goals):SDGs 优先事项的选择

正在写&#xff0c;不断更新&#xff0c;别着急。。。 4. SDGs 优先事项的选择 4.1 基于SDG密度分布图选择优先事项 虽然每个可持续发展目标的接近度矩阵和中心性度量的结果是通用的&#xff0c;并创建了基本的可持续发展目标网络&#xff0c;但由于各国在网络的不同部分取得…