当前位置: 首页 > news >正文

【AI Agent系列】【MetaGPT多智能体学习】3. 开发一个简单的多智能体系统,兼看MetaGPT多智能体运行机制

本系列文章跟随《MetaGPT多智能体课程》(https://github.com/datawhalechina/hugging-multi-agent),深入理解并实践多智能体系统的开发。

本文为该课程的第四章(多智能体开发)的第一篇笔记。主要记录下多智能体的运行机制及跟着教程,实现一个简单的多智能体系统。

系列笔记

  • 【AI Agent系列】【MetaGPT多智能体学习】0. 环境准备 - 升级MetaGPT 0.7.2版本及遇到的坑
  • 【AI Agent系列】【MetaGPT多智能体学习】1. 再理解 AI Agent - 经典案例和热门框架综述
  • 【AI Agent系列】【MetaGPT多智能体学习】2. 重温单智能体开发 - 深入源码,理解单智能体运行框架

文章目录

  • 系列笔记
  • 0. 多智能体间互通的方式 - Enviroment组件
    • 0.1 多智能体间协作方式简介
    • 0.2 Environment组件 - 深入源码
      • 0.2.1 参数介绍
      • 0.2.2 add_roles函数 - 承载角色
      • 0.2.3 publish_message函数 - 接收角色发布的消息 / 环境中的消息被角色得到
      • 0.2.4 run函数 - 运行入口
  • 1. 开发一个简单的多智能体系统
    • 1.1 多智能体需求描述
    • 1.2 代码实现
      • 1.2.1 学生智能体
      • 1.2.2 老师智能体
      • 1.2.3 创建多智能体交流的环境
      • 1.2.4 运行
      • 1.2.5 完整代码
  • 2. 总结

0. 多智能体间互通的方式 - Enviroment组件

0.1 多智能体间协作方式简介

在上次课中,我也曾写过 多智能体运行机制 的笔记(这篇文章:【AI Agent系列】【MetaGPT】【深入源码】智能体的运行周期以及多智能体间如何协作)。其中我自己通过看源码,总结出了MetaGPT多智能体间协作的方式:

(1)每一个Role都在不断观察环境中的信息(_observe函数)
(2)当观察到自己想要的信息后,就会触发后续相应的动作
(3)如果没有观察到想要的信息,则会一直循环观察
(4)执行完动作后,会将产生的msg放到环境中(publish_message),供其它Role智能体来使用。

现在再结合《MetaGPT多智能体》课程的教案,发现还是理解地有些浅了,我只关注了智能体在关注自己想要的信息,观察到了之后就开始行动,而忽略了其背后的基础组件 - Enviroment。

0.2 Environment组件 - 深入源码

MetaGPT中对Environment的定义:环境,承载一批角色,角色可以向环境发布消息,可以被其他角色观察到。短短一句话,总结三个功能:

  • 承载角色
  • 接收角色发布的消息
  • 环境中的消息被角色得到

下面我们分开来细说。

0.2.1 参数介绍

首先来看下 Environment 的参数:

class Environment(ExtEnv):"""环境,承载一批角色,角色可以向环境发布消息,可以被其他角色观察到Environment, hosting a batch of roles, roles can publish messages to the environment, and can be observed by other roles"""model_config = ConfigDict(arbitrary_types_allowed=True)desc: str = Field(default="")  # 环境描述roles: dict[str, SerializeAsAny["Role"]] = Field(default_factory=dict, validate_default=True)member_addrs: Dict["Role", Set] = Field(default_factory=dict, exclude=True)history: str = ""  # For debugcontext: Context = Field(default_factory=Context, exclude=True)
  • desc:环境的描述
  • roles:字典类型,指定当前环境中的角色
  • member_addrs:字典类型,表示当前环境中的角色以及他们对应的状态
  • history:记录环境中发生的消息记录
  • context:当前环境的一些上下文信息

0.2.2 add_roles函数 - 承载角色

def add_roles(self, roles: Iterable["Role"]):"""增加一批在当前环境的角色Add a batch of characters in the current environment"""for role in roles:self.roles[role.profile] = rolefor role in roles:  # setup system message with rolesrole.set_env(self)role.context = self.context

从源码中看,这个函数的功能有两个:

(1)给 Environment 的 self.roles 参数赋值,上面我们已经知道它是一个字典类型,现在看来,它的 key 为 role 的 profile,值为 role 本身。

疑问: role 的 profile 默认是空(profile: str = ""),可以没有值,那如果使用者懒得写profile,这里会不会最终只有一个 Role,导致无法实现多智能体?欢迎讨论交流。

(2)给添加进来的 role 设置环境信息

Role的 set_env 函数源码如下,它又给env设置了member_addrs。有点绕?

def set_env(self, env: "Environment"):"""Set the environment in which the role works. The role can talk to the environment and can also receivemessages by observing."""self.rc.env = envif env:env.set_addresses(self, self.addresses)self.llm.system_prompt = self._get_prefix()self.set_actions(self.actions)  # reset actions to update llm and prefix

通过 add_roles 函数,将 role 和 Environment 关联起来。

0.2.3 publish_message函数 - 接收角色发布的消息 / 环境中的消息被角色得到

Environment 中的 publish_message 函数是 Role 在执行完动作之后,将自身产生的消息发布到环境中调用的接口。Role的调用方式如下:

def publish_message(self, msg):"""If the role belongs to env, then the role's messages will be broadcast to env"""if not msg:returnif not self.rc.env:# If env does not exist, do not publish the messagereturnself.rc.env.publish_message(msg)

通过上面的代码来看,一个Role只能存在于一个环境中?

然后看下 Environment 中源码:

def publish_message(self, message: Message, peekable: bool = True) -> bool:"""Distribute the message to the recipients.In accordance with the Message routing structure design in Chapter 2.2.1 of RFC 116, as already plannedin RFC 113 for the entire system, the routing information in the Message is only responsible forspecifying the message recipient, without concern for where the message recipient is located. How toroute the message to the message recipient is a problem addressed by the transport framework designedin RFC 113."""logger.debug(f"publish_message: {message.dump()}")found = False# According to the routing feature plan in Chapter 2.2.3.2 of RFC 113for role, addrs in self.member_addrs.items():if is_send_to(message, addrs):role.put_message(message)found = Trueif not found:logger.warning(f"Message no recipients: {message.dump()}")self.history += f"\n{message}"  # For debugreturn True

其中重点是这三行代码,检查环境中的所有Role是否订阅了该消息(或该消息是否应该发送给环境中的某个Role),如果订阅了,则调用Role的put_message函数,Role的 put_message函数的作用是将message放到本身的msg_buffer中:

for role, addrs in self.member_addrs.items():if is_send_to(message, addrs):role.put_message(message)

这样就实现了将环境中的某个Role的Message放到环境中,并通知给环境中其它的Role的机制。

0.2.4 run函数 - 运行入口

run函数的源码如下:

async def run(self, k=1):"""处理一次所有信息的运行Process all Role runs at once"""for _ in range(k):futures = []for role in self.roles.values():future = role.run()futures.append(future)await asyncio.gather(*futures)logger.debug(f"is idle: {self.is_idle}")

k = 1, 表示处理一次消息?为什么要有这个值,难道还能处理多次?意义是什么?

该函数其实就是遍历一遍当前环境中的所有Role,然后运行Role的run函数(运行单智能体)。

Role的run里面,就是用该环境观察信息,行动,发布信息到环境。这样多个Role的运行就通过 Environment 串起来了,这些之前已经写过了,不再赘述,见:【AI Agent系列】【MetaGPT】【深入源码】智能体的运行周期以及多智能体间如何协作。

1. 开发一个简单的多智能体系统

复现教程中的demo。

1.1 多智能体需求描述

  • 两个智能体:学生 和 老师
  • 任务及预期流程:学生写诗 —> 老师给改进意见 —> 学生根据意见改进 —> 老师给改进意见 —> … n轮 … —> 结束

1.2 代码实现

1.2.1 学生智能体

学生智能体的主要内容就是根据指定的内容写诗。

因此,首先定义一个写诗的Action:WritePoem

然后,定义学生智能体,指定它的动作就是写诗(self.set_actions([WritePoem])

那么它什么时候开始动作呢?通过 self._watch([UserRequirement, ReviewPoem]) 设置其观察的信息。当它观察到环境中有了 UserRequirement 或者 ReviewPoem 产生的信息之后,开始动作。UserRequirement为用户的输入信息类型。

class WritePoem(Action):name: str = "WritePoem"PROMPT_TEMPLATE: str = """Here is the historical conversation record : {msg} .Write a poem about the subject provided by human, Return only the content of the generated poem with NO other texts.If the teacher provides suggestions about the poem, revise the student's poem based on the suggestions and return.your poem:"""async def run(self, msg: str):prompt = self.PROMPT_TEMPLATE.format(msg = msg)rsp = await self._aask(prompt)return rspclass Student(Role):name: str = "xiaoming"profile: str = "Student"def __init__(self, **kwargs):super().__init__(**kwargs)self.set_actions([WritePoem])self._watch([UserRequirement, ReviewPoem])async def _act(self) -> Message:logger.info(f"{self._setting}: ready to {self.rc.todo}")todo = self.rc.todomsg = self.get_memories()  # 获取所有记忆# logger.info(msg)poem_text = await WritePoem().run(msg)logger.info(f'student : {poem_text}')msg = Message(content=poem_text, role=self.profile,cause_by=type(todo))return msg

1.2.2 老师智能体

老师的智能体的任务是根据学生写的诗,给出修改意见。

因此创建一个Action为ReviewPoem

然后,创建老师的智能体,指定它的动作为Review(self.set_actions([ReviewPoem])

它的触发实际应该是学生写完诗以后,因此,加入self._watch([WritePoem])

class ReviewPoem(Action):name: str = "ReviewPoem"PROMPT_TEMPLATE: str = """Here is the historical conversation record : {msg} .Check student-created poems about the subject provided by human and give your suggestions for revisions. You prefer poems with elegant sentences and retro style.Return only your comments with NO other texts.your comments:"""async def run(self, msg: str):prompt = self.PROMPT_TEMPLATE.format(msg = msg)rsp = await self._aask(prompt)return rspclass Teacher(Role):name: str = "laowang"profile: str = "Teacher"def __init__(self, **kwargs):super().__init__(**kwargs)self.set_actions([ReviewPoem])self._watch([WritePoem])async def _act(self) -> Message:logger.info(f"{self._setting}: ready to {self.rc.todo}")todo = self.rc.todomsg = self.get_memories()  # 获取所有记忆poem_text = await ReviewPoem().run(msg)logger.info(f'teacher : {poem_text}')msg = Message(content=poem_text, role=self.profile,cause_by=type(todo))return msg

1.2.3 创建多智能体交流的环境

前面我们已经知道了多智能体之间的交互需要一个非常重要的组件 - Environment。

因此,创建一个供多智能体交流的环境,通过 add_roles 加入智能体。

然后,当用户输入内容时,将该内容添加到环境中publish_message,从而触发相应智能体开始运行。这里cause_by=UserRequirement代表消息是由用户产生的,学生智能体关心这类消息,观察到之后就开始行动了。

classroom = Environment()classroom.add_roles([Student(), Teacher()])classroom.publish_message(Message(role="Human", content=topic, cause_by=UserRequirement,send_to='' or MESSAGE_ROUTE_TO_ALL),peekable=False,
)

1.2.4 运行

加入相应头文件,指定交互次数,就可以开始跑了。注意交互次数,直接决定了你的程序的效果和你的钱包!

import asynciofrom metagpt.actions import Action, UserRequirement
from metagpt.logs import logger
from metagpt.roles import Role
from metagpt.schema import Message
from metagpt.environment import Environmentfrom metagpt.const import MESSAGE_ROUTE_TO_ALLasync def main(topic: str, n_round=3):while n_round > 0:# self._save()n_round -= 1logger.debug(f"max {n_round=} left.")await classroom.run()return classroom.historyasyncio.run(main(topic='wirte a poem about moon'))

1.2.5 完整代码

import asynciofrom metagpt.actions import Action, UserRequirement
from metagpt.logs import logger
from metagpt.roles import Role
from metagpt.schema import Message
from metagpt.environment import Environmentfrom metagpt.const import MESSAGE_ROUTE_TO_ALLclassroom = Environment()class WritePoem(Action):name: str = "WritePoem"PROMPT_TEMPLATE: str = """Here is the historical conversation record : {msg} .Write a poem about the subject provided by human, Return only the content of the generated poem with NO other texts.If the teacher provides suggestions about the poem, revise the student's poem based on the suggestions and return.your poem:"""async def run(self, msg: str):prompt = self.PROMPT_TEMPLATE.format(msg = msg)rsp = await self._aask(prompt)return rspclass ReviewPoem(Action):name: str = "ReviewPoem"PROMPT_TEMPLATE: str = """Here is the historical conversation record : {msg} .Check student-created poems about the subject provided by human and give your suggestions for revisions. You prefer poems with elegant sentences and retro style.Return only your comments with NO other texts.your comments:"""async def run(self, msg: str):prompt = self.PROMPT_TEMPLATE.format(msg = msg)rsp = await self._aask(prompt)return rspclass Student(Role):name: str = "xiaoming"profile: str = "Student"def __init__(self, **kwargs):super().__init__(**kwargs)self.set_actions([WritePoem])self._watch([UserRequirement, ReviewPoem])async def _act(self) -> Message:logger.info(f"{self._setting}: ready to {self.rc.todo}")todo = self.rc.todomsg = self.get_memories()  # 获取所有记忆# logger.info(msg)poem_text = await WritePoem().run(msg)logger.info(f'student : {poem_text}')msg = Message(content=poem_text, role=self.profile,cause_by=type(todo))return msgclass Teacher(Role):name: str = "laowang"profile: str = "Teacher"def __init__(self, **kwargs):super().__init__(**kwargs)self.set_actions([ReviewPoem])self._watch([WritePoem])async def _act(self) -> Message:logger.info(f"{self._setting}: ready to {self.rc.todo}")todo = self.rc.todomsg = self.get_memories()  # 获取所有记忆poem_text = await ReviewPoem().run(msg)logger.info(f'teacher : {poem_text}')msg = Message(content=poem_text, role=self.profile,cause_by=type(todo))return msgasync def main(topic: str, n_round=3):classroom.add_roles([Student(), Teacher()])classroom.publish_message(Message(role="Human", content=topic, cause_by=UserRequirement,send_to='' or MESSAGE_ROUTE_TO_ALL),peekable=False,)while n_round > 0:# self._save()n_round -= 1logger.debug(f"max {n_round=} left.")await classroom.run()return classroom.historyasyncio.run(main(topic='wirte a poem about moon'))
  • 运行结果

在这里插入图片描述

2. 总结

总结一下整个流程吧,画了个图。

在这里插入图片描述
从最外围环境 classroom开始,用户输入的信息通过 publish_message 发送到所有Role中,通过Role的 put_message 放到自身的 msg_buffer中。

当Role运行run时,_observemsg_buffer中提取信息,然后只过滤自己关心的消息,例如Teacher只过滤出来自WritePoem的,其它消息虽然在msg_buffer中,但不处理。同时,msg_buffer中的消息会存入memory中。

run完即执行完相应动作后,通过publish_message将结果消息发布到环境中,环境的publish_message又将这个消息发送个全部的Role,这时候所有的Role的msg_buffer中都有了这个消息。完成了智能体间信息的一个交互闭环。


站内文章一览

在这里插入图片描述

相关文章:

【AI Agent系列】【MetaGPT多智能体学习】3. 开发一个简单的多智能体系统,兼看MetaGPT多智能体运行机制

本系列文章跟随《MetaGPT多智能体课程》(https://github.com/datawhalechina/hugging-multi-agent),深入理解并实践多智能体系统的开发。 本文为该课程的第四章(多智能体开发)的第一篇笔记。主要记录下多智能体的运行…...

机器学习-面经(part7、无监督学习)

机器学习面经系列的其他部分如下所示: 机器学习-面经(part1) 机器学习-面经(part2)-交叉验证、超参数优化、评价指标等内容 机器学习-面经(part3)-正则化、特征工程面试问题与解答合集机器学习-面经(part4)-决策树共5000字的面试问题与解答…...

teknoparrot命令行启动游戏

官方github cd 到teknoparrot解压目录 cd /d E:\mn\TeknoParrot2_cp1\GameProfiles启动游戏 TeknoParrotUi.exe --profile游戏配置文件游戏配置文件位置/UserProfiles,如果UserProfiles文件夹里没有那就在/GameProfiles,在配置文件里将游戏路径加入之间,或者打开模拟器设置 …...

停止Tomcat服务的方式

运行脚本文件停止 运行Tomcat的bin目录中提供的停止服务的脚本文件 关闭命令 # sh方式 sh shutdown.sh# ./方式 ./shutdown.sh操作步骤 运行结束进程停止 查看Tomcat进程,获得进程id kill进程命令 # 执行命令结束进程 kill -9 65358 操作步骤 注意 kill命令是…...

多线程相关面试题(2024大厂高频面试题系列)

1、聊一下并行和并发有什么区别? 并发是同一时间应对多件事情的能力,多个线程轮流使用一个或多个CPU 并行是同一时间动手做多件事情的能力,4核CPU同时执行4个线程 2、说一下线程和进程的区别? 进程是正在运行程序的实例&#xff…...

mysql 时间精度问题

timestamp到2038年,还有14年时间,一个系统如果能活到那一刻也是相当不错了。 这里先看一下个datetime的问题,下面的插入数据的时间戳是2024-03-06 21:20:50.839 INSERT INTO psi_io_balance ( id, as_id, bill_date, order_id, busi_type, direction, c…...

基于python的爬虫原理和管理系统实现(代码下载)

Python实现爬虫的原理如下: 发送请求:使用Python中的库,如Requests或urllib,向目标网站发送HTTP请求,获取网页的内容。 解析网页:使用Python中的库,如BeautifulSoup或lxml,对获取的…...

IOS 设置UIViewController为背景半透明浮层弹窗,查看富文本图片详情

使用场景&#xff1a;UIViewController1 打开 UIViewController2&#xff08;背景半透明弹窗&#xff09; 案例&#xff1a;打开富文本网页<img>图片的url查看图片详情 WKWebView WKNavigationDelegate代理方法设置js代码点击事件 ///注册添加图片标签点击js方法 - …...

网络层介绍

网络层是OSI模型中的第三层&#xff0c;也称为网络协议层。它主要负责在源主机和目标主机之间提供数据通信的路径选择和控制。网络层通过使用源和目标主机的网络地址来实现数据包的路由和转发。 以下是网络层的一些主要功能&#xff1a; 路由选择&#xff1a;网络层使用路由选…...

springboot/ssm酒店客房管理系统Java在线酒店预约预定平台web

springboot/ssm酒店客房管理系统Java在线酒店预约预定平台web 基于springboot(可改ssm)vue项目 开发语言&#xff1a;Java 框架&#xff1a;springboot/可改ssm vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;…...

分布式测试插件 pytest-xdist 使用详解

使用背景&#xff1a; 大型测试套件&#xff1a;当你的测试套件非常庞大&#xff0c;包含了大量的测试用例时&#xff0c;pytest-xdist可以通过并行执行来加速整体的测试过程。它利用多个进程或计算机的计算资源&#xff0c;可以显著减少测试执行的时间。高计算资源需求&#…...

【S32K3 MCAL配置】-1.1-GPIO配置及其应用-点亮LED灯(基于MCAL)

目录(共13页精讲,手把手教你S32K3从入门到精通) 实现的架构:基于MCAL层 前期准备工作: 1 创建一个FREERTOS工程...

【软件工程】软件工程定义、软件危机以及软件生命周期

&#x1f338;博主主页&#xff1a;釉色清风&#x1f338;文章专栏&#xff1a;软件工程&#x1f338; 今日语录&#xff1a;What matters isn’t how others think of your ambitions but how fervently you cling to them. 软件工程系列&#xff0c;主要根据老师上课所讲提及…...

24计算机考研深大经验分享(计算机专业考研综合安排)

文章目录 背景科目选择高数选课一轮二轮冲刺阶段 线代一轮二轮 概率论计算机学科专业基础408数据结构计算机组成原理操作系统计算机网络总结 英语政治 末言 背景 首先贴一下初试成绩。这篇分享主要是给零基础的同学使用的&#xff0c;基础好的同学可以自行了解补充一下&#xf…...

【知识整理】MySQL数据库开发设计规范

一、规范背景与目的 MySQL数据库与 Oracle、 SQL Server 等数据库相比&#xff0c;有其内核上的优势与劣势。我们在使用MySQL数据库的时候需要遵循一定规范&#xff0c;扬长避短。 本规范旨在帮助或指导RD、QA、OP等技术人员做出适合线上业务的数据库设计。在数据库变更和处理…...

Vue自定义组件实现v-model

前言 v-model 实际上就是 $emit(input) 以及 props:value 的组合语法糖。 1.封装自定义组件 要在 Vue 中实现自定义组件的 v-model 功能&#xff0c;你可以通过使用 model 选项来定义组件的 prop 和事件。以下是一个示例代码&#xff0c;演示如何实现一个自定义组件并使用 v…...

【Linux】Linux网络故障排查与解决指南

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Linux ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 检查网络连接状态&#xff1a; 检查路由表&#xff1a; 检查DNS配置&#xff1a; 检查网络连接状态&#xff1a; 检查防火墙设…...

跟着cherno手搓游戏引擎【27】升级2DRenderer(添加旋转)

水节&#xff0c;添加了旋转的DrawQuad&#xff1a; Renderer2D.h: #pragma once #include "OrthographicCamera.h" #include"Texture.h" namespace YOTO {class Renderer2D{public://为什么渲染器是静态的&#xff1a;static void Init();static void …...

中医舌苔笔记

舌诊时按照舌尖-舌中-舌根-舌侧的顺序进行观察。 先看舌体再看舌苔&#xff0c;30秒左右。 如果一次望舌判断不清&#xff0c;可令病人休息3~5分钟后&#xff0c;重新观察一次 舌诊脏腑部位分属图 舌体 胖嫩而边有齿痕为气虚、阳虚。 薄白而润为风寒&#xff1b; 薄白而燥…...

Facebook的社交未来:元宇宙时代的数字共融

引言&#xff1a; 随着科技的不断进步和社会的快速发展&#xff0c;人们对于社交网络的需求和期待也在不断演变。在这个数字化时代&#xff0c;元宇宙的概念逐渐引发了人们对社交体验的重新思考。作为全球最大的社交网络之一&#xff0c;Facebook正在积极探索元宇宙时代的社交…...

2024护网面试题精选(一)

0x00.基础漏洞篇 00-TOP10漏洞 1.SQL注入 2.失效的身份认证和会话管理 3.跨站脚本攻击XSS 4.直接引用不安全的对象 5.安全配置错误 6.敏感信息泄露 7.缺少功能级的访问控制 8.跨站请求伪造CSRF 9.实验含有已知漏洞的组件 10.未验证的重定向和转发 01-SQL注入漏洞 …...

如何制作一个简单html网页

要制作一个简单的HTML网页&#xff0c;可以按照以下步骤进行&#xff1a; 创建一个新的文本文件并将其保存为.html文件&#xff08;例如&#xff0c;index.html&#xff09;。 打开文本文件&#xff0c;并使用以下基本的HTML结构开始编写代码&#xff1a; <!DOCTYPE html…...

React富文本编辑器开发(七)接口与辅助函数

接口 我们知道Slate使用纯 JSON 数据对象&#xff0c;只要这些数据符合接口标准就行。也就是说每一个节点都有一个接口标准与之对应。比如文本节点&#xff1a; interface Text {text: string }在实例这些接口数据的同时我们也可以增加额外的属性&#xff0c;这根据我们的实际…...

【conda】conda卸载并重新安装指定版本软件package

1. conda卸载软件包 可先通过 conda list 查看已当前环境已安装的软件包 conda uninstall your_package如果卸载失败, 可通过pip卸载 pip uninstall your_package2. 安装指定版本的软件包 先搜索可安装的软件包版本, 如 conda search --full-name protobuf再安装对应的软件版本…...

项目设计方案规范参考

在软件架构设计中&#xff0c;以下是一个常见的软件架构设计模版&#xff0c;供参考&#xff1a; 1. 业务需求分析 确定系统的业务需求和功能需求。 分析用户需求&#xff0c;确定系统的核心功能和非功能需求。 2. 架构设计原则 SOLID 原则&#xff08;单一职责、开放封闭、里…...

LVS----DR模式

一、LVS-DR工作原理 1、LVS-DR数据包流向分析 客户端发送请求到Director Server (负载均衡器)&#xff0c;请求的数据报文&#xff08;源IP是CIP&#xff0c;目标IP是VIP&#xff09;到达内核空间。Director Server 和Real Server 在同一个网络中&#xff0c;数据通过二层数据…...

操作系统(笔记)(一)

1、操作系统的功能和目标 1.1功能 存储管理文件管理设备管理处理机管理进程管理 1.2目标 方便性&#xff1a;操作系统作为用户与计算机硬件系统之间的接口&#xff0c;提供了直观的命令和界面&#xff0c;使得用户能够更容易地操作计算机。有效性&#xff1a;操作系统旨在提…...

Redis线程模型解析

引言 Redis是一个高性能的键值对&#xff08;key-value&#xff09;内存数据库&#xff0c;以其卓越的读写速度和灵活的数据类型而广受欢迎。在Redis 6.0之前的版本中&#xff0c;它采用的是一种独特的单线程模型来处理客户端的请求。尽管单线程在概念上似乎限制了其扩展性和并…...

ros2 launch如何控制node的启动顺序

ros2 launch如何控制node的启动顺序 文章目录 引言如何写launch文件启动流程图具体launch代码总结引言 本文用来说明如何控制ros2 launch 节点的先后顺序,我们有时候需要一个节点启动完成后再启动其它节点,实现这个功能有两种方式: 在launch.py时写event根据事件触发使用li…...

Android13 framework层添加关机接口

framework层修改&#xff1a; t0_sys/frameworks/base/core/api/current.txt method RequiresPermission(android.Manifest.permission.REBOOT) public void reboot(Nullable String);method public void rebootp();t0_sys/frameworks/base/core/java/android/os/IPowerManager…...