ROS-ROS通信机制-常用API

文章目录

  • 1.初始化
  • 2.话题和服务相关对象
    • 2.1 C++
      • 2.1.1发布对象
      • 2.1.2 订阅对象
      • 2.1.3 服务对象
      • 2.1.4 客户端对象
    • 2.2 Python
      • 2.2.1 发布对象
      • 2.2.2 订阅对象
      • 2.2.3 服务对象
      • 2.2.4 客户端对象
  • 3.回旋函数
  • 4.时间
  • 5.其他函数

1.初始化

C++初始化

/** @brief ROS初始化函数。** 该函数可以解析并使用节点启动时传入的参数(通过参数设置节点名称、命名空间...) ** 该函数有多个重载版本,如果使用NodeHandle建议调用该版本。 ** \param argc 参数个数(n+1,第一个是文件自身)* \param argv 参数列表(数组)* \param name 节点名称,需要保证其唯一性,不允许包含命名空间* \param options 节点启动选项,被封装进了ros::init_options**argc与argv的使用:如果按照ROS中的特定格式传入实参,那么ROS可以加以使用,比如用来设置全局参数、给节点重命名等。**options使用:*节点名称需要保证唯一,会导致同一个节点不能重复启动。ROS中当有重名的节点启动时,之前的节点会被关闭。特定场景下,需要一个节点多次启动且能正常运行。可以在初始化时ros::init_options::AnonymousName;这样在创建节点时,会在节点名称后加上一个随机数,从而避免重名问题。**/
void init(int &argc, char **argv, const std::string& name, uint32_t options = 0);

Python初始化

def init_node(name, argv=None, anonymous=False, log_level=None, disable_rostime=False, disable_rosout=False, disable_signals=False, xmlrpc_port=0, tcpros_port=0):"""在ROS msater中注册节点@param name: 节点名称,必须保证节点名称唯一,节点名称中不能使用命名空间(不能包含 '/')@type  name: str@param anonymous: 取值为 true 时,为节点名称后缀随机编号@type anonymous: bool"""

2.话题和服务相关对象

2.1 C++

在 roscpp 中,话题和服务的相关对象一般由 NodeHandle 创建。
NodeHandle有一个重要作用是可以用于设置命名空间,这是后期的重点,但是本章暂不介绍。

2.1.1发布对象

对象获取:

/**
* \brief 根据话题生成发布对象
*
* 在 ROS master 注册并返回一个发布者对象,该对象可以发布消息
*
* 使用示例如下:
*
*   ros::Publisher pub = handle.advertise<std_msgs::Empty>("my_topic", 1);
*
* \param topic 发布消息使用的话题
*
* \param queue_size 等待发送给订阅者的最大消息数量
*
* \param latch (optional) 如果为 true,该话题发布的最后一条消息将被保存,并且后期当有订阅者连接时会将该消息发送给订阅者
*latch设置为 true 的作用:以静态地图发布为例,方案1:使用固定频率发送地图数据,但效率低;方案2:可以将地图发布对象的 latch 设置为true,并且发布方只发送一次数据,每当订阅者连接时,将地图发送给订阅者,提高了数据的发送效率。
*
* \return 调用成功时,会返回一个发布对象
*
*模板:被发布的消息的类型
*
*/
template <class M>
Publisher advertise(const std::string& topic, uint32_t queue_size, bool latch = false)

消息发布函数:

/**
* 发布消息          
*/
template <typename M>
void publish(const M& message) const

2.1.2 订阅对象

对象获取:

/*** \brief 生成某个话题的订阅对象** 该函数将根据给定的话题在ROS master 注册,并自动连接相同主题的发布方,每接收到一条消息,都会调用回调* 函数,并且传入该消息的共享指针,该消息不能被修改,因为可能其他订阅对象也会使用该消息。* * 使用示例如下:void callback(const std_msgs::Empty::ConstPtr& message)
{
}ros::Subscriber sub = handle.subscribe("my_topic", 1, callback);*
* \param M [template] M 是指消息类型
* \param topic 订阅的话题
* \param queue_size 消息队列长度,超出长度时,头部的消息将被弃用
* \param fp 当订阅到一条消息时,需要执行的回调函数
* \return 调用成功时,返回一个订阅者对象,失败时,返回空对象
* void callback(const std_msgs::Empty::ConstPtr& message){...}
ros::NodeHandle nodeHandle;
ros::Subscriber sub = nodeHandle.subscribe("my_topic", 1, callback);
if (sub) // Enter if subscriber is valid
{
...
}*/
template<class M>
Subscriber subscribe(const std::string& topic, uint32_t queue_size, void(*fp)(const boost::shared_ptr<M const>&), const TransportHints& transport_hints = TransportHints())

2.1.3 服务对象

对象获取:

/**
* \brief 生成服务端对象
*
* 该函数可以连接到 ROS master,并提供一个具有给定名称的服务对象。
*
* 使用示例如下:
\verbatim
bool callback(std_srvs::Empty& request, std_srvs::Empty& response)
{
return true;
}ros::ServiceServer service = handle.advertiseService("my_service", callback);
\endverbatim
*
* \param service 服务的主题名称
* \param srv_func 接收到请求时,需要处理请求的回调函数
* \return 请求成功时返回服务对象,否则返回空对象:
\verbatim
bool Foo::callback(std_srvs::Empty& request, std_srvs::Empty& response)
{
return true;
}
ros::NodeHandle nodeHandle;
Foo foo_object;
ros::ServiceServer service = nodeHandle.advertiseService("my_service", callback);
if (service) // Enter if advertised service is valid
{
...
}
\endverbatim*/
template<class MReq, class MRes>
ServiceServer advertiseService(const std::string& service, bool(*srv_func)(MReq&, MRes&))

2.1.4 客户端对象

对象获取:

/** * @brief 创建一个服务客户端对象** 当清除最后一个连接的引用句柄时,连接将被关闭。** @param service_name 服务主题名称*/template<class Service>ServiceClient serviceClient(const std::string& service_name, bool persistent = false, const M_string& header_values = M_string())

请求发送函数:

/*** @brief 发送请求* 返回值为 bool 类型,true,请求处理成功,false,处理失败。*/template<class Service>bool call(Service& service)

等待服务函数1:

/*** ros::service::waitForService("addInts");* \brief 等待服务可用,否则一致处于阻塞状态* \param service_name 被"等待"的服务的话题名称* \param timeout 等待最大时常,默认为 -1,可以永久等待直至节点关闭* \return 成功返回 true,否则返回 false。*/
ROSCPP_DECL bool waitForService(const std::string& service_name, ros::Duration timeout = ros::Duration(-1));

等待服务函数2:

/**
* client.waitForExistence();
* \brief 等待服务可用,否则一致处于阻塞状态
* \param timeout 等待最大时常,默认为 -1,可以永久等待直至节点关闭
* \return 成功返回 true,否则返回 false。
*/
bool waitForExistence(ros::Duration timeout = ros::Duration(-1));

2.2 Python

2.2.1 发布对象

对象获取:

class Publisher(Topic):"""在ROS master注册为相关话题的发布方"""def __init__(self, name, data_class, subscriber_listener=None, tcp_nodelay=False, latch=False, headers=None, queue_size=None):"""Constructor@param name: 话题名称 @type  name: str@param data_class: 消息类型@param latch: 如果为 true,该话题发布的最后一条消息将被保存,并且后期当有订阅者连接时会将该消息发送给订阅者@type  latch: bool@param queue_size: 等待发送给订阅者的最大消息数量@type  queue_size: int"""

消息发布函数:

def publish(self, *args, **kwds):"""发布消息"""

2.2.2 订阅对象

对象获取:

class Subscriber(Topic):"""类注册为指定主题的订阅者,其中消息是给定类型的。"""def __init__(self, name, data_class, callback=None, callback_args=None,queue_size=None, buff_size=DEFAULT_BUFF_SIZE, tcp_nodelay=False):"""Constructor.@param name: 话题名称@type  name: str@param data_class: 消息类型@type  data_class: L{Message} class@param callback: 处理订阅到的消息的回调函数@type  callback: fn(msg, cb_args)@param queue_size: 消息队列长度,超出长度时,头部的消息将被弃用"""

2.2.3 服务对象

对象获取:

class Service(ServiceImpl):"""声明一个ROS服务使用示例::s = Service('getmapservice', GetMap, get_map_handler)"""def __init__(self, name, service_class, handler,buff_size=DEFAULT_BUFF_SIZE, error_handler=None):"""@param name: 服务主题名称 ``str``@param service_class:服务消息类型@param handler: 回调函数,处理请求数据,并返回响应数据@type  handler: fn(req)->resp"""

2.2.4 客户端对象

对象获取:

class ServiceProxy(_Service):"""创建一个ROS服务的句柄示例用法::add_two_ints = ServiceProxy('add_two_ints', AddTwoInts)resp = add_two_ints(1, 2)"""def __init__(self, name, service_class, persistent=False, headers=None):"""ctor.@param name: 服务主题名称@type  name: str@param service_class: 服务消息类型@type  service_class: Service class"""

请求发送函数:

def call(self, *args, **kwds):"""发送请求,返回值为响应数据"""

等待服务函数:

def wait_for_service(service, timeout=None):"""调用该函数时,程序会处于阻塞状态直到服务可用@param service: 被等待的服务话题名称@type  service: str@param timeout: 超时时间@type  timeout: double|rospy.Duration"""

3.回旋函数

C++
在ROS程序中,频繁的使用了 ros::spin() 和 ros::spinOnce() 两个回旋函数,可以用于处理回调函数。
1.spinOnce()

/*** \brief 处理一轮回调** 一般应用场景:*     在循环体内,处理所有可用的回调函数* */
ROSCPP_DECL void spinOnce();

2.spin()

/** * \brief 进入循环处理回调 */
ROSCPP_DECL void spin();

3.二者比较

  • 相同点:二者都用于处理回调函数;
  • 不同点:ros::spin() 是进入了循环执行回调函数,而 ros::spinOnce()只会执行一次回调函数(没有循环),在 ros::spin() 后的语句不会执行到,而 ros::spinOnce() 后的语句可以执行。(没太理解的感觉)

Python

def spin():"""进入循环处理回调 """

4.时间

ROS中时间相关的API是极其常用,比如:获取当前时刻、持续时间的设置、执行频率、休眠、定时器…都与时间相关。
C++
1.时刻
获取时刻,或是设置指定时刻:

ros::init(argc,argv,"hello_time");
ros::NodeHandle nh;//必须创建句柄,否则时间没有初始化,导致后续API调用失败
ros::Time right_now = ros::Time::now();//将当前时刻封装成对象;当前时刻为 now 被调用执行的那一刻
ROS_INFO("当前时刻:%.2f",right_now.toSec());//获取距离 1970年01月01日 00:00:00 的秒数
ROS_INFO("当前时刻:%d",right_now.sec);//获取距离 1970年01月01日 00:00:00 的秒数ros::Time someTime(100,100000000);// 参数1:秒数  参数2:纳秒
ROS_INFO("时刻:%.2f",someTime.toSec()); //100.10
ros::Time someTime2(100.3);//直接传入 double 类型的秒数
ROS_INFO("时刻:%.2f",someTime2.toSec()); //100.30

2.持续时间
设置一个时间区间(间隔):

ROS_INFO("当前时刻:%.2f",ros::Time::now().toSec());
ros::Duration du(10);//持续10秒钟,参数是double类型的,以秒为单位
du.sleep();//按照指定的持续时间休眠
ROS_INFO("持续时间:%.2f",du.toSec());//将持续时间换算成秒
ROS_INFO("当前时刻:%.2f",ros::Time::now().toSec());

3.持续时间与时刻运算
为了方便使用,ROS中提供了时间与时刻的运算:

ROS_INFO("时间运算");
ros::Time now = ros::Time::now();
ros::Duration du1(10);
ros::Duration du2(20);
ROS_INFO("当前时刻:%.2f",now.toSec());
//1.time 与 duration 运算
ros::Time after_now = now + du1;
ros::Time before_now = now - du1;
ROS_INFO("当前时刻之后:%.2f",after_now.toSec());
ROS_INFO("当前时刻之前:%.2f",before_now.toSec());//2.duration 之间相互运算
ros::Duration du3 = du1 + du2;
ros::Duration du4 = du1 - du2;
ROS_INFO("du3 = %.2f",du3.toSec());
ROS_INFO("du4 = %.2f",du4.toSec());// ros::Time nn = now + before_now;//异常
ros::Duration du5 = now-before_now//小结 1.时刻与持续时间可以执行加减运算
//     2.持续时间可以执行加减运算
//     3.时刻之间只可以相减,不可以相加

4.设置运行频率

ros::Rate rate(1);//指定频率
while (true)
{ROS_INFO("-----------code----------");rate.sleep();//休眠,休眠时间 = 1 / 频率。
}

5.定时器
ROS 中内置了专门的定时器,可以实现与 ros::Rate 类似的效果:

ros::NodeHandle nh;//必须创建句柄,否则时间没有初始化,导致后续API调用失败// ROS 定时器/**
* \brief 创建一个定时器,按照指定频率调用回调函数。
*
* \param period 时间间隔
* \param callback 回调函数
* \param oneshot 如果设置为 true,只执行一次回调函数,设置为 false,就循环执行。
* \param autostart 如果为true,返回已经启动的定时器,设置为 false,需要手动启动。
*///Timer createTimer(Duration period, const TimerCallback& callback, bool oneshot = false,//                bool autostart = true) const;// ros::Timer timer = nh.createTimer(ros::Duration(0.5),doSomeThing);ros::Timer timer = nh.createTimer(ros::Duration(0.5),doSomeThing,true);//只执行一次// ros::Timer timer = nh.createTimer(ros::Duration(0.5),doSomeThing,false,false);//需要手动启动// timer.start();ros::spin(); //必须 spin

定时器的回调函数:

void doSomeThing(const ros::TimerEvent &event){ROS_INFO("-------------");ROS_INFO("event:%s",std::to_string(event.current_real.toSec()).c_str());
}

Python
1.时刻
获取时刻,或是设置指定时刻:

# 获取当前时刻
right_now = rospy.Time.now()
rospy.loginfo("当前时刻:%.2f",right_now.to_sec())
rospy.loginfo("当前时刻:%.2f",right_now.to_nsec())
# 自定义时刻
some_time1 = rospy.Time(1234.567891011)
some_time2 = rospy.Time(1234,567891011)
rospy.loginfo("设置时刻1:%.2f",some_time1.to_sec())
rospy.loginfo("设置时刻2:%.2f",some_time2.to_sec())# 从时间创建对象
# some_time3 = rospy.Time.from_seconds(543.21)
some_time3 = rospy.Time.from_sec(543.21) # from_sec 替换了 from_seconds
rospy.loginfo("设置时刻3:%.2f",some_time3.to_sec())

2.持续时间
设置一个时间区间(间隔):

# 持续时间相关API
rospy.loginfo("持续时间测试开始.....")
du = rospy.Duration(3.3)
rospy.loginfo("du1 持续时间:%.2f",du.to_sec())
rospy.sleep(du) #休眠函数
rospy.loginfo("持续时间测试结束.....")

3.持续时间与时刻运算
为了方便使用,ROS中提供了时间与时刻的运算:

rospy.loginfo("时间运算")
now = rospy.Time.now()
du1 = rospy.Duration(10)
du2 = rospy.Duration(20)
rospy.loginfo("当前时刻:%.2f",now.to_sec())
before_now = now - du1
after_now = now + du1
dd = du1 + du2
# now = now + now #非法
rospy.loginfo("之前时刻:%.2f",before_now.to_sec())
rospy.loginfo("之后时刻:%.2f",after_now.to_sec())
rospy.loginfo("持续时间相加:%.2f",dd.to_sec())

4.设置运行频率

# 设置执行频率
rate = rospy.Rate(0.5)
while not rospy.is_shutdown():rate.sleep() #休眠rospy.loginfo("+++++++++++++++")

5.定时器
ROS 中内置了专门的定时器,可以实现与 ros::Rate 类似的效果:

#定时器设置
"""    
def __init__(self, period, callback, oneshot=False, reset=False):Constructor.@param period: 回调函数的时间间隔@type  period: rospy.Duration@param callback: 回调函数@type  callback: function taking rospy.TimerEvent@param oneshot: 设置为True,就只执行一次,否则循环执行@type  oneshot: bool@param reset: if True, timer is reset when rostime moved backward. [default: False]@type  reset: bool
"""
rospy.Timer(rospy.Duration(1),doMsg)
# rospy.Timer(rospy.Duration(1),doMsg,True) # 只执行一次
rospy.spin()

回调函数:

def doMsg(event):rospy.loginfo("+++++++++++")rospy.loginfo("当前时刻:%s",str(event.current_real))

5.其他函数

在发布实现时,一般会循环发布消息,循环的判断条件一般由节点状态来控制,C++中可以通过 ros::ok() 来判断节点状态是否正常,而 python 中则通过 rospy.is_shutdown() 来实现判断,导致节点退出的原因主要有如下几种:

  • 节点接收到了关闭信息,比如常用的 ctrl + c 快捷键就是关闭节点的信号;
  • 同名节点启动,导致现有节点退出;
  • 程序中的其他部分调用了节点关闭相关的API(C++中是ros::shutdown(),python中是rospy.signal_shutdown())

另外,日志相关的函数也是极其常用的,在ROS中日志被划分成如下级别:

  • DEBUG(调试):只在调试时使用,此类消息不会输出到控制台;
  • INFO(信息):标准消息,一般用于说明系统内正在执行的操作;
  • WARN(警告):提醒一些异常情况,但程序仍然可以执行;
  • ERROR(错误):提示错误信息,此类错误会影响程序运行;
  • FATAL(严重错误):此类错误将阻止节点继续运行。

C++
1.节点状态判断

/** \brief 检查节点是否已经退出**  ros::shutdown() 被调用且执行完毕后,该函数将会返回 false** \return true 如果节点还健在, false 如果节点已经火化了。*/
bool ok();

2.节点关闭函数

/*
*   关闭节点
*/
void shutdown();

3.日志函数

ROS_DEBUG("hello,DEBUG"); //不会输出
ROS_INFO("hello,INFO"); //默认白色字体
ROS_WARN("Hello,WARN"); //默认黄色字体
ROS_ERROR("hello,ERROR");//默认红色字体
ROS_FATAL("hello,FATAL");//默认红色字体

Python
1.节点状态判断

def is_shutdown():"""@return: True 如果节点已经被关闭@rtype: bool"""

2.节点关闭函数

def signal_shutdown(reason):"""关闭节点@param reason: 节点关闭的原因,是一个字符串@type  reason: str"""
def on_shutdown(h):"""节点被关闭时调用的函数@param h: 关闭时调用的回调函数,此函数无参@type  h: fn()"""

3.日志函数

rospy.logdebug("hello,debug")  #不会输出
rospy.loginfo("hello,info")  #默认白色字体
rospy.logwarn("hello,warn")  #默认黄色字体
rospy.logerr("hello,error")  #默认红色字体
rospy.logfatal("hello,fatal") #默认红色字体

参考:
[1]Autolabor-ROS机器人入门课程《ROS理论与实践》季基础教程
[2]【Autolabor初级教程】ROS机器人入门
[3]胡春旭.ROS机器人开发实践[M].机械工业出版社,2018.

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

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

相关文章

vxe-table 右键菜单+权限控制(v3)

1.menu-config 是用于配置右键菜单的属性。通过 menu-config 属性&#xff0c;定义右键菜单的内容、显示方式和样式。 通过 menu-config 属性配置了右键菜单&#xff0c;其中的 options 属性定义了右键菜单的选项。用户在表格中右键点击时&#xff0c;将会弹出包含这些选项的自…

flutter 顺逆时针旋转图片铺满比例区域

最近遇到一个项目需求&#xff0c;这里记录下。将图片进行顺时针旋转90和逆时针90&#xff0c;保证图片都铺满矩形框区域 import dart:async; import dart:io; import dart:math; import dart:ui as ui;import package:flutter/foundation.dart; import package:flutter/mater…

嵌入式实习难找怎么办?

今日话题&#xff0c;嵌入式实习难找怎么办&#xff1f;个人建议如果找不到实习机会&#xff0c;可以回归学习嵌入式所需的知识&#xff0c;积累项目经验或者回顾之前参与过的项目&#xff0c;将它们整理复盘。如果还有时间&#xff0c;可以再尝试找实习&#xff0c;如果找不到…

GSIL:GitHub敏感信息泄露监控工具使用

GSIL:GitHub敏感信息泄露监控工具使用 1.工具概述2.安装3.配置4.用法1.工具概述 凭据和API可能会泄露在公司的公共存储库或github公司的用户的存储库中,GSIL用于实时监控GitHub敏感信息泄露,并发送告警通知 2.安装 git clone git@github.com:FeeiCN/GSIL.git pip install …

ARM NEON加速介绍及使用示例

ARM NEON 是 ARM 架构中的SIMD (Single Instruction, Multiple Data) 扩展&#xff0c;它提供了一组专用的指令和寄存器&#xff0c;用于高效地处理并行数据。在 Linux 内核中&#xff0c;ARM NEON 驱动提供了对 NEON 寄存器和指令的支持&#xff0c;以便在内核中利用 NEON 进行…

【开题报告】基于SpringBoot的个人博客的设计与实现

1.选题背景 &#xff08;1&#xff09;技术研究需求&#xff1a; 当今社会&#xff0c;个人博客作为一种重要的网络传播形式&#xff0c;已经成为许多人记录、分享个人见解和经验的重要平台。然而&#xff0c;现有的个人博客系统在易用性、扩展性和定制化方面存在一定的局限性…

(第69天)可刷新 PDB

介绍 从 Oracle 12CR2 版本开始支持可刷新 PDB,在 19C 版本后功能更加强大,为什么会衍生出这个技术呢? 很多生产的 PDB 数据量很大,如果使用传统的方式进行克隆操作可能需要相当长的时间,并且克隆之后的数据无法随着源库更新而刷新,为了尽量减少对生产系统库的影响,可刷…

anolisos8.8安装显卡+CUDA工具+容器运行时支持(containerd/docker)+k8s部署GPU插件

anolisos8.8安装显卡及cuda工具 一、目录 1、测试环境 2、安装显卡驱动 3、安装cuda工具 4、配置容器运行时 5、K8S集群安装nvidia插件 二、测试环境 操作系统&#xff1a;Anolis OS 8.8 内核版本&#xff1a;5.10.134-13.an8.x86_64 显卡安装版本&#xff1a;525.147.05 c…

java学生选课系统 数据库版

首先让我们创建一个数据库让我们向表中插入数据然后查询它

ubuntu 20.04.6 server 服务器 下载与安装(配置静态IP)

下载地址&#xff1a;https://releases.ubuntu.com/20.04.6/ubuntu-20.04.6-live-server-amd64.iso 第一步&#xff1a; 准备U盘&#xff0c;使用软碟通将下载好的镜像写入到U盘中 软碟通网址&#xff1a;https://www.cn.ultraiso.net/xiazai.html 点击&#xff1a;文件 ->…

odoo16 全局搜索菜单

实现效果: 主要思路: 参考原生的many2one字段的相关源码&#xff0c;添加 systray 组件

sql server导出与导入

本文解决&#xff1a;不同版本sql server复制表、导数据&#xff1b;把数据库的结构和全部数据从2016版导入到2014版。 分离数据为mdf,ldf后&#xff0c;导入过程中无权限、被占用问题。 使用脚本&#xff08;.sql文件&#xff09; 导出 选中你要导出的数据库&#xff0c;右…

算法通关村第十七关 | 黄金挑战 | 跳跃游戏

1.跳跃游戏 原题&#xff1a;力扣55. 逐步判断下一步的覆盖范围&#xff0c;根据范围去推断是否能到达终点&#xff0c;不用计较每一步走到哪里。 public boolean canJump(int[] nums) {// 题目规定 nums 长度大于等于1if (nums.length 1) {return true;}int cover 0;// f…

python 中Windows编程一些心得

主要思路 当我们显示所有消息的信息时&#xff0c;我们可以知道Windows后台是如何传递消息给我们&#xff0c;但是并不会把所有东西写进开发文档 &#xff0c;这有一定的原因 但是 我们要自己去理解或者猜想开发者思路或者根据反馈结果来分析消息的作用&#xff0c;不然永远只…

java面试题-Dubbo和zookeeper运行原理

远离八股文&#xff0c;面试大白话&#xff0c;通俗且易懂 看完后试着用自己的话复述出来。有问题请指出&#xff0c;有需要帮助理解的或者遇到的真实面试题不知道怎么总结的也请评论中写出来&#xff0c;大家一起解决。 java面试题汇总-目录-持续更新中 分布式注册中心和服务调…

线程|如何实现守护线程?

文章目录 守护线程是什么&#xff1f;守护线程有哪些应用场景?守护线程如何实现&#xff1f; 守护线程是什么&#xff1f; 守护线程是一种特殊的线程&#xff0c;它是在后台运行的线程&#xff0c;主要用于执行一些如垃圾回收、内存管理等“后台”任务。这些线程通常不会直接…

自定义字符串排序

说在前面 &#x1f388;不知道大家对于算法的学习是一个怎样的心态呢&#xff1f;为了面试还是因为兴趣&#xff1f;不管是出于什么原因&#xff0c;算法学习需要持续保持。 一、题目描述 给定两个字符串 order 和 s 。order 的所有单词都是 唯一 的&#xff0c;并且以前按照一…

HNU计算机视觉作业三

前言 选修的是蔡mj老师的计算机视觉&#xff0c;上课还是不错的&#xff0c;但是OpenCV可能需要自己学才能完整把作业写出来。由于没有认真学&#xff0c;这门课最后混了80多分&#xff0c;所以下面作业解题过程均为自己写的&#xff0c;并不是标准答案&#xff0c;仅供参考 …

鸿蒙开发之状态管理@State

1、视图数据双向绑定 鸿蒙开发采用的声明式UI&#xff0c;利用状态驱动UI的更新。其中State被称作装饰器&#xff0c;是一种状态管理的方式。 状态&#xff1a;指的是被装饰器装饰的驱动视图更新的数据。 视图&#xff1a;是指用户看到的UI渲染出来的界面。 之所以成为双向…

计算机网络实验8

实验目的&#xff1a; 通过实验掌握下列知识&#xff1a; 掌握小型园区网络综合设计。 实验过程分析&#xff1a;配置命令 1&#xff09; 罗列步骤2&#xff09;中各设备的配置命令。 Internet: interface ser1/0 ip address 100.1.1.1 24 quit RTA: sysname RTA_LXL interfa…