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

C++笔记(体系结构与内核分析)

1.OOP面向对象编程 vs. GP泛型编程

  • OOP将data和method放在一起,目的是通过封装、继承、多态提高软件的可维护性和可扩展性
  • GP将data和method分开,可以将任何容器与任何算法结合使用,只要容器满足塞饭所需的迭代器类型

2.算法与仿函数的区别

bool strLonger(const string &s1, const string &s2)
{return s1.size() < s2.size();
}// 算法
cout << "max of zoo and hello:" << max(string("zoo"), string("hello")) << endl;
// 仿函数
cout << "max of zoo and hello:" << max(string("zoo"), string("hello"), strLonger) << endl;

3.泛化、特化、偏特化

  • 泛化:支持广泛的数据类型和情况,而不是针对特定类型
  • 特化:为特定类型或一组类型提供特定的实现
#include <iostream>// General template
template <typename T>
void print(T arg) {std::cout << "General print: " << arg << std::endl;
}// Specialization for const char*
template <>
void print<const char*>(const char* arg) {std::cout << "Specialized print for const char*: " << arg << std::endl;
}int main() {print(123);             // Uses general templateprint("Hello, world");  // Uses specialized template
}
  • 偏特化:针对特定类型组合提供优化的行为或特殊实现。完全特化需要指定模板的所有参数,偏特化只需指定部分参数,或对参数施加某些约束。
    • 第一种偏特化处理第二个模板参数为 int 的情况。
    • 第二种偏特化处理两个模板参数相同的情况。
#include <iostream>// 基本模板
template <typename T, typename U>
class MyClass {
public:void print() {std::cout << "Base template\\n";}
};// 偏特化:特化第二个类型为 int 的情况
template <typename T>
class MyClass<T, int> {
public:void print() {std::cout << "Partially specialized template for T and int\\n";}
};// 偏特化:特化两个类型都为相同类型的情况
template <typename T>
class MyClass<T, T> {
public:void print() {std::cout << "Partially specialized template for T, T\\n";}
};int main() {MyClass<double, double> myClass1;  // 会匹配 MyClass<T, T>MyClass<double, int> myClass2;     // 会匹配 MyClass<T, int>MyClass<double, char> myClass3;    // 会匹配基本模板 MyClass<T, U>myClass1.print();  // 输出: Partially specialized template for T, TmyClass2.print();  // 输出: Partially specialized template for T and intmyClass3.print();  // 输出: Base template
}

4.分配器allocates

分配器(allocators)是用来管理内存分配和回收的对象。

  • 在 VC6 中,operator new() 通常通过调用 malloc() 实现, malloc() 函数不仅会开辟用户请求的内存外,还会引入额外的内存开销
void* operator new(size_t size) {void* p = malloc(size);if (p == 0) // 如果malloc失败,则抛出std::bad_alloc异常throw std::bad_alloc();return p;
}
  • 例如:当我们需要分配512个整型数据时
int *p = allocator<int>().allocate(512,(int *)0);
allocator<int>().deallocate(p,512);
  • 在 VC6 / BC++ / G++中,allocator 类都是使用 operator new 来分配内存,并使用 operator delete 来释放内存。其中,operator new() 通常通过调用 malloc() 实现开辟内存,operator delete() 通常通过调用 free() 实现回收内存:
// VC6 STL中容器对allocator的使用
template<class _Ty, class _A=allocator<_Ty>>  // 调用allocator类
class vector
{ ...
};
template <typename T>
class allocator {
public:typedef size_t    size_type; // size_t是一个无符合整型数据类型typedef ptrdiff_t difference_type;  // 表示同一个数组中任意两个元素之间的差异typedef T*        pointer;typedef T         value_type;pointer allocate(size_type n, const void* hint = 0) {return (pointer) (::operator new(n * sizeof(value_type)));}void deallocate(pointer p, size_type n) {::operator delete(p);}
}
  • 在GCC2.9中
// VC6 STL中容器对allocator的使用
template<class T, class Alloc = alloc>  // 调用allocator类
class vector
{ ...
};

 

①内存池:由一系列内存块组成,每块预分配一定数量的内存。

②自由列表:每个固定大小的内存块都有自己的自由列表。

③大小分类:根据内存请求的大小被分类到不同的自由列表。

  • GCC4.9所附的标准库,其中**__pool_alloc就是GCC2.9中的alloc**

    // 使用方法
    vector<string, __gnn_cxx::__pool_alloc<string>> vec;
    

5.容器的分类

 

6.容器list

G2.9版本:

template <class T, class Alloc = alloc>
class list{
protected:typeof __list_node<T> list_node;  // 1号代码块
public:typeof list_node* link_type;typeof __list_iterator<T,T&,T*> iterator;  // 2号代码块
protected:link_type node;
}
// 1号代码块
template <class T>
struct __list_node {void* prev;void* next;T data;
};
// 2号代码块
template <class T,class Ref,class Ptr>
struct __list_iterator{typedef bidirectional_iterator_tag iterator_category;  // (1)typedef T  value_type;  // (2)typedef Ptr pointer;  // (3)typedef Ref reference;  // (4)typedef ptrdiff_t difference_type;  // (5)typedef __list_node<T> list_node;typedef list_node* list_type;typedef __list_iterator<T,Ref,Ptr> self;link_type node;reference operator*() const{ return (*node).data; }  // 返回引用pointer operator->() const{ return &(operator *());}  // 返回指针。获得该对象的内存地址,即一个指向该对象的指针self& operator++()   // i++{ node = (link_type) ((*node).next); return *this; // 返回自身的引用}// (*node).next是一个 __list_node<T>* 类型的值,加上(list_type)是显式类型转换// (*node).next 等价于 node->next 等价于 (&(*node))->next;// node只是一个迭代器的指针,不是迭代器本身// self&表示返回迭代器的引用self operator++(int)   // ++i{ self tmp = *this; ++*this; return tmp;}
};
  • 前缀递增 (operator++()) 将迭代器向前移动到下一个元素
  • 后缀递增 (operator++(int)) 返回迭代器的一个临时副本(在递增前的状态),然后再递增迭代器。
  • 内置 -> 操作符 用于直接从指针访问对象成员。
  • 重载的 operator->() 提供了一种方式,通过迭代器对象模拟原生指针的行为,允许通过迭代器间接访问对象成员。
  • (*node).next等价于node->next 等价于 (&(*node))->next

G4.9版本:

template<typename _Tp, typename _Alloc=std::allocator<_Tp>>
class list:protected_List_base<_Tp,_Alloc>
{
public:typedef _List_iterator<_Tp> iterator;
}
  • template<typename _Tp, typename _Alloc = std::allocator<_Tp>>
    • 这是一个类模板,接受两个模板参数。
    • _Tp 表示列表中要存储的数据类型。
    • _Alloc 是分配器类型,用于控制链表中元素的内存分配。这个参数有一个默认值,即 std::allocator<_Tp>,这是 C++ 标准库提供的一种通用内存分配器。
  • : protected _List_base<_Tp, _Alloc>
    • list 类从 _List_base 类继承而来,使用保护(protected)继承。这意味着 _List_base 中的公共和保护成员在 list 类中将变为保护成员。
    • _List_base 是一个实现链表基础功能的类
template<typename _Tp>
struct _List_iterator
{typedef _Tp* pointer;typedef _Tp& reference;...
};
// 自身类型的指针使得可以从任何一个节点开始
// 沿着链表向前或向后移动,这对于双向遍历和双向操作非常重要。
struct _List_node_base
{_List_node_base* _M_next;_List_node_base* _M_prev;
};
template<typename _Tp>
struct _List_node:public _List_node_base
{_Tp _M_data;
};

7.Iterator必须提供5中associated types

算法提问:

template<typename T>
incline void
algorithm(T first, T last)  // 迭代器
{...T::iterator_categoryT::value_typeT::pointerT::referenceT::difference_type...
};

迭代器回答:

template <class T,class Ref,class Ptr>
struct __list_iterator{typedef bidirectional_iterator_tag iterator_category;  // (1)typedef T  value_type;  // (2)typedef Ptr pointer;  // (3)typedef Ref reference;  // (4)typedef ptrdiff_t difference_type;  // (5)...
};

8. iterator_traits 类型萃取

但当我们向算法中传入的是指针,而不是迭代器时,就需要用到traits。也就是说,iterator_traits 为所有类型的迭代器(包括原生指针)提供统一的方式来访问迭代器的属性,是在 <iterator> 头文件中定义的。

作用:

std::iterator_traits 模板用于提取迭代器相关的类型信息。

举例:

#include<iostream>
#include<iterator>
#include<vector>template<typename Iterator>
void print_vector(Iterator first, Iterator last)
{// using关键字用来定义类型的别名// typename关键字告诉编译器这是一个依赖于模版参数Iterator的类型,而不是变量using ValueType = typename iterator_traits<Iterator>::value_type;
}int main()
{vector<int> v = {1,2,3,4,5};print_vector(v.begin(), v.end());
}
// 当Iterator是一个类时
template<class Iterator>
struct iterator_traits
{typedef typename Iterator::value_type value_type;
};// 两种偏特化情况
// 当Iterator是一个普通指针时
// 如int*,那么T为int,得到value_type就被定义为“int”
template<class T>
struct iterator_traits<T*>
{typedef T value_type;
};// 当Iterator是一个常量指针(指针的指向可以修改,指针指向的值不能修改)
template<class T>
struct iterator_traits<const T*>
{typedef T value_type;
};
  • Iterator若是int*,ValueType 就是 int
  • Iterator若是const int*,ValueType 还是 int
  • 因为如果 ValueType 是 const int,后续再使用ValueType创建其他容器时,就会受到限制。因为标准库中的容器(如 std::vector)不能存储常量类型的元素,它们需要能被赋值和移动。

完整的iterator_traits:

template<class Iterator>
struct iterator_traits
{typedef typename Iterator::iterator_category iterator_category;typedef typename Iterator::value_type value_type;typedef typename Iterator::pointer iterator_category;typedef typename Iterator::reference reference;typedef typename Iterator::difference_type difference_type;
};template<class T>
struct iterator_traits<T*>
{typedef random_access_iterator_tag iterator_category;typedef T value_type;typedef ptrdiff_t difference_type;typedef T* pointer;typedef T& reference;
};template<class T>
struct iterator_traits<const T*>
{typedef random_access_iterator_tag iterator_category;typedef T value_type;typedef ptrdiff_t difference_type;typedef const T* pointer;typedef const T& reference;
};

9.容器vector

定义:

template <class T, class Alloc = std::allocator<T>>
class vector
{
public:typedef T value_type;typedef T* pointer;typedef &T reference;typedef size_t size_type;
protected:iterator **start**;iterator **finish**;iterator **end_of_range**;Allocator alloc;
public:iterator begin() { return **start**;}iterator end() { return **finish**;}size_type size const { return size_type(end() - start());}size_type capacity() const{ return size_type(**end_of_storage** - begin());}bool empty() const { return begin() == end();}reference operator[](size_type n}{return *(begin()+n);referebce front() {return *begin();}reference back() {return *(end()-1);}
};

push_back操作源码:

template <class T, class Alloc=std::allocator<T>>
void push_back(const T& value)
{if(finish == end_of_storage)  // 原始空间不足{size_type old_size = size();// old_size == 0:当前vector中没有任何元素,新分配的存储空间至少有一个元素的容量// old_size != 0:分配新的容量将是当前大小的两倍, 称为指数增长size_type new_capacity = old_size == 0 ? 1 : 2 * old_size;iterator new_start = alloc.allocator(new_capacity);iterator new_finsih = new_start;try{// 将原数据移动到新空间for(iterator old_iter = start; old_iter != finish; ){alloc.construct(new_finish++, *old_iter);alloc.destroy(old_iter++);}// 添加新元素alloc.construct(new_finish++, value);}catch(...){// 如果构造失败,释放已分配的内存for(iterator it=new_start; it!=new_finish; ++it){alloc.destory(it);}alloc.deallocate(new_start, new_capacity);throw;  // 重新抛出当前异常}// 释放旧空间if (start) {alloc.deallocate(start, end_of_storage - start);}// 更新指针start = new_start;finish = new_finish;end_of_storage = start + new_capacity;} else {alloc.construct(finish++, value); // 有足够空间,直接构造新元素}
}

vector的迭代器iterator:

template <class T, class Alloc = alloc>
class vector
{
public:typedef T value_type;typedef T* iterator;
};// 调用方法
vectot<int> v;
vector<int>::iterator it = v.begin();

10.容器deque

 


// BufSize是指缓冲区buffer的长度
template<class T,class Alloc = alloc, size_t BufSize=0>
class deque
{
public:typedef T value_type;typedef size_t size_type;typedef __deque_iterator<T,T&,T*,BufSiz> iterator;
protected:typedef T** map_pointer;  // 指向指针数组的指针
protected:iterator start;iterator finish;map_point map;  // 指向指针数组的指针,每一个都指向一个缓冲区size_type map_size;
public:iterator begin() {return start;}iterator end() {return finish;}size_type size() {return finish - start;}...
};

deque的迭代器iterator:

template<class T, class Ref, class Ptr, size_t BufSize>
struct __deque_iterator
{typedef random_access_iterator_tag iterator_category;typedef T value_type;typedef Ref reference; // T&typedef Ptr pointer; // T*typedef size_t size_type;typedef ptrdiff_t difference_type;typedef T** map_pointer;typedef __deque_iterator<T,Ref,Ptr,BufSiz> self;T* **cur**;T* **first**;T* **last**;map_point **node**;
};

相关文章:

C++笔记(体系结构与内核分析)

1.OOP面向对象编程 vs. GP泛型编程 OOP将data和method放在一起&#xff0c;目的是通过封装、继承、多态提高软件的可维护性和可扩展性GP将data和method分开&#xff0c;可以将任何容器与任何算法结合使用&#xff0c;只要容器满足塞饭所需的迭代器类型 2.算法与仿函数的区别 …...

c++ 唤醒指定线程

在C中&#xff0c;直接唤醒一个特定的线程并不像在Java的Thread类中有interrupt()方法或者某些操作系统特定的API&#xff08;如POSIX的pthread_cond_signal或Windows的SetEvent&#xff09;那样简单。C标准库没有提供一个直接的方法来"唤醒"一个正在等待的线程。然而…...

java报错:使用mybatis plus查询一个只返回一条数据的sql,却报错返回了1000多条

今天遇到一个问题 系统线上问题&#xff0c;经常出现这样的问题&#xff0c;刚重启系统时不报错了&#xff0c;可是运行一段时间又会出现。sql已经写了limit 1&#xff0c;mybatis的debug日志也返回total为1&#xff0c;可是却报错返回了1805条数据 乍一看&#xff0c;感觉太不…...

AI图书推荐:利用生成式AI实现业务流程超自动化

《利用生成式AI实现业务流程超自动化》&#xff08;Hyperautomation with Generative AI&#xff09;这本书探索了广泛的用例和示例&#xff0c;展示了超自动化在不同行业、领域和特定部门的多样化应用&#xff0c; 让您熟悉UiPath、Automation Anywhere和IBM等流行工具和平台&…...

什么事防抖和节流,有什么区别,如何实现

防抖和节流&#xff0c;本质上是优化高频率执行代码的一种手段&#xff0c;比如&#xff1a;resize、scroll、keypress、mousemove这些事件在触发的时候&#xff0c;会不断调用绑定在事件上的回调函数&#xff0c;这样极大浪费资源&#xff0c;降低前端性能。 为了优化体验&am…...

PanguSync大数据量初始化脚本

由于数据库增量同步软件PanguSync初始化最大超时时间为600s,如果初始数据量很大&#xff0c;第一次部署时可能会超时&#xff0c;可以先停止任务&#xff0c;使用以下Sql语句进行初始化&#xff0c;以下语句可以分步执行&#xff0c;初始化完成后&#xff0c;后续无需再执行耗时…...

DELL T630服务器iDRAC分辨率调整办法

对于Dell T630服务器的iDRAC分辨率调整&#xff0c;您需要登录到iDRAC的Web界面。以下是详细的步骤&#xff1a; 登录iDRAC&#xff1a;在浏览器中输入iDRAC的IP地址&#xff0c;然后使用用户名&#xff08;通常是“root”&#xff09;和密码登录。 导航到虚拟控制台&#xff…...

您真的会高效使用 Mac 吗?

文章目录 屏幕的保养快捷键预览修改文件名查看文件属性搜索编辑复制&#xff0c;粘贴&#xff0c;剪切&#xff0c;撤销删除 跳转窗口屏幕截图声音Dock强制退出查字典神奇的Option键鼠标与触控板切换桌面与应用程序打开通知中心打开Mission Control 安装与卸载Mac应用程序压缩和…...

Vue11 Vue3完结撒花

shallowRef和shallowReactive shallowRef 作用&#xff1a;创建一个响应式数据&#xff0c;但只对顶层属性进行响应式处理 用法 let myVar shallowRef(initialValue)特点&#xff1a;只跟踪引用值变化&#xff0c;不关心值内部的属性变化 案例 <template><div c…...

CodeTop 高频笔试题总结(持续更新)

&#x1f3c6; 频率从高到低排序 &#x1f468;‍&#x1f3eb; 参考的频率数据&#xff1a;CodeTop &#x1f468;‍&#x1f3eb; 力扣hot100 无重复字符的最长子串 双指针 滑动窗口 哈希&#x1f468;‍&#x1f3eb; 力扣hot100 反转链表 指针 递归 一题多解&#x1f468;‍…...

类和对象一(从封装开始讲述)

目录&#xff1a; 一.封装 二.封装扩展之包&#xff0c;自定义包 三.访问限定符 四.static成员 一.封装&#xff1a;封装&#xff1a;将数据和操作数据的方法进行有机结合&#xff0c;隐藏对象的属性和实现细节&#xff0c;仅对外公开接口来和对象进行 交互。面向对象…...

LeetCode100题总结

LeetCode100题总结 前言LeetCode100题总结题型梳理双指针11. 盛最多水的容器234.回文链表75.颜色分类206.反转链表142.环形链表215.三数之和 滑动窗口3. 无重复字符的最长子串209. 长度最小的子数组438. 找到字符串中所有字母异位词 广搜102. 二叉树的层序遍历200. 岛屿数量617…...

基于截断傅里叶级数展开的抖动波形生成

1、背景 抖动是影响信号完整性的重要因素。随着信号速率的不断提高&#xff0c;抖动的影响日益显著。仿真生成抖动时钟或抖动信号&#xff0c;对系统极限性能验证具有重要意义。抖动是定义在时域上的概念&#xff0c;它表征真实跳变位置(如跳边沿或过零点)与理想跳变位…...

图片标注编辑平台搭建系列教程(9)——支持撤销的画线行为

文章目录 背景渲染行为mouseDownmouseMovemouseDbclick总结背景 编辑器中的绘制,要想做的足够好,是需要支持撤销形点的,因为作业员在绘制过程中,可能会点错位置,需要及时撤销,否则影响编辑效率。撤销我们知道,需要通过ID编辑器的history的undo来实现,那么意味着,每一…...

赶紧收藏!2024 年最常见 100道 Java 基础面试题(四十一)

上一篇地址&#xff1a;赶紧收藏&#xff01;2024 年最常见 100道 Java 基础面试题&#xff08;四十&#xff09;-CSDN博客 八十一、tcp为什么要三次握手&#xff0c;两次不行吗&#xff1f;为什么&#xff1f; TCP&#xff08;传输控制协议&#xff09;使用三次握手&#xf…...

使用自关联方法处理多表关系

使用自关联方法处理多表关系 这里通过省市区之间的关系来解释自关联的情况 在设置地址的过程中 , 不可避免的需要设置 , 省份 ,市以及区 而省市区三者之间的具有一定的关联关系 一个省份对应多个市 一个市对应多个区 如果通过设置主表从表关系则需要设置三张标分别对应省…...

annaconda详细解读换源文件

annaconda换源详细解读文件 annaconda换源详细解读文件 annaconda换源详细解读文件 #踩坑/annaconda换源详细解读通道问题 如何准确使用国内源高效安装GPU版本的Pytorch - 知乎 文件中的custom通道&#xff0c;需要自己手动添加到默认通道里面&#xff0c;记得后面更上/包名…...

AI大模型系列:编写高质量提示(prompt)的实践技巧

AI大模型系列专栏 文章收录于AI大模型系列专栏 文明基石&#xff0c;文字与数字的起源与演变自然语言处理&#xff0c;从规则到统计的演变AI魔法师&#xff0c;提示工程的力量编写高质量提示&#xff08;prompt&#xff09;的小技巧编写高质量提示&#xff08;prompt&#xf…...

汽车EDI:安通林Antolin EDI 项目案例

安通林&#xff08;Antolin&#xff09;是一家全球性的汽车零部件制造商&#xff0c;专注于汽车内饰系统和零部件的生产&#xff0c;致力于创新和采用先进的技术。近年来 安通林Antolin 推动其供应商部署EDI系统&#xff0c;使得双方能够通过EDI传输业务单据&#xff0c;极大提…...

今日arXiv最热NLP大模型论文:揭露大语言模型短板,北京大学提出事件推理测试基准

人工智能领域又一里程碑时刻&#xff01;北京大学、北京智源人工智能研究院等机构联合推出大型事件推理评测基准 。这是首个同时在知识和推理层面全面评估大模型事件推理能力的数据集。 总所周知&#xff0c;事件推理需要丰富的事件知识和强大的推理能力&#xff0c;涉及多种推…...

windows系统安装Ubuntu子系统

安装前先在 控制面板 中打开 程序与功能选项 &#xff0c;点击 启用或关闭Windows功能&#xff1a; 勾选 适用于 Linux的Windows子系统 和 虚拟机平台 、 Hyper-v 。 重启电脑后再 Microsoft Store Windows应用商店 中下载合适的Ubuntu版本。 运行Ubuntu程序&#xff0c;如出现…...

电脑复制和粘贴的时候会出现Hello!

电脑不管是Microsoft Excel还是Microsoft Word复制之后粘贴过来就出现HELLO&#xff0c;当复制粘贴文件的时候就会出现WINFILE&#xff1b; 具体现象看下面两个图片&#xff1a; 这是因为winfile 文件病毒&#xff08;幽灵蠕虫病毒&#xff09;,每月的28号发作&#xff1b; 症状…...

AI新视界:探索Baidu Comate的前沿科技

前言 Baidu Comate&#xff08;智能代码助手&#xff09;是基于文心大模型&#xff0c;结合百度积累多年的编程现场大数据和外部优秀开源数据&#xff0c;打造的新一代编码辅助工具。拥有代码智能、场景丰富、创造价值、广泛应用等多重产品优势&#xff0c;可实现“帮你想、帮…...

唐山知识付费系统搭建教程,女性创业难吗?2017十佳女性创业故事:黑科技创业“女神”

女性创业难吗?2017十佳女性创业故事&#xff1a;黑科技创业“女神”!创业似乎一直是一个比较热门的话题&#xff0c;女性创业也是一个很有争议的问题。女性创业难吗?看看2017十佳女性创业故事&#xff1a;黑科技创业“女神”。 阿里研究院、中国企业家木兰汇、阿里巴巴创新中…...

Hotcoin Research | 模块化将是大势所趋:拆解模块化区块链的现状和未来

关于模块化区块链叙事的讨论源于Celestia和其代币TIA的亮眼表现。实际上&#xff0c;模块化是未来区块链设计的主要发展方向和大势所趋。模块化区块链就像乐高积木一样&#xff0c;将区块链系统拆分为可重用的模块&#xff0c;通过定制组合可实现不同功能的区块链网络。这种灵活…...

Unity VR在编辑器下开启Quest3透视(PassThrough)功能

现在有个需求是PC端串流在某些特定时候需要开启透视。我研究了两天发现一些坑,记录一下方便查阅,也给没踩坑的朋友一些思路方案。 先说结论,如果要打PC端或者在Unity编辑器中开启,那么OpenXR当前是不行的可能还需要一个长期的过程,必须需要切换到Oculus。当然Unity官方指…...

使用 git rebase 还是 git merge,优缺点

在开发过程中使用 git rebase 还是 git merge&#xff0c;优缺点分别是什么&#xff1f; - 知乎 看一下gerrit的模式 永远rebase 绝对禁用merge 每一个commit都是一个完整的功能 保持清晰直观的提交历史 所以&#xff0c;main 分支是万万不能使用 rebase 的&#xff01;&#…...

李飞飞团队 AI4S 最新洞察:16 项创新技术汇总,覆盖生物/材料/医疗/问诊……

不久前&#xff0c;斯坦福大学 Human-Center Artificial Intelligence (HAI) 研究中心重磅发布了《2024年人工智能指数报告》。 作为斯坦福 HAI 的第七部力作&#xff0c;这份报告长达 502 页&#xff0c;全面追踪了 2023 年全球人工智能的发展趋势。相比往年&#xff0c;扩大了…...

springboot整合rabbitmq的不同工作模式理解

前提是已经安装并启动了rabbitmq&#xff0c;并且项目已经引入rabbitmq&#xff0c;完成了配置。 不同模式所需参数不同&#xff0c;生产者可以根据参数不同使用重载的convertAndSend方法。而消费者均是直接监听某个队列。 不同的交换机是实现不同工作模式的关键组件.每种交换…...

Ansible(二)

一、Playbook基础 1.1 Playbook定义 Playbook其实是Ansible服务的一个配置文件&#xff0c;Ansible使用Playbook的YAML语言配置编写成操作需求&#xff0c;实现对远端主机或策略部署&#xff0c;实现对远端主机的控制与管理。 1.2 Playbook组成 Tasks&#xff1a;任务&…...