谈谈对 GMP 的简单认识
犹记得最开始学习 golang 的时候,大佬们分享 GMP 模型的时候,总感觉云里雾里,听了半天,并没有一个很清晰的概念,不知 xmd 是否会有这样的体会
虽然 golang 入门很简单,但是对于理解 golang 的设计思想和原理,还是需要一定时间的积累和沉淀,更多的应该是思想上的沉淀
希望这篇文章能够对你了解 golang 的 GMP 模型有一点帮助
文章分别从一下三个方面来谈谈我对 GMP 模型认识
- golang 中调度器的变化及其作用
- 有了进程,线程,为什么会出现协程
- GMP 模型中的 G,M,P 分别都做着什么样的事情
golang 中的调度器的变化及其作用
调度器,scheduler
怎么理解呢?调度器就像是一个管理者,负责安排事项,负责调度不同人在指定时间在某个岗位上完成自己的价值交付
正如 linux 调度器一样,将就绪的进程调度成执行状态,或者将执行状态的进程,打断,变成阻塞状态,再变成就绪状态
比如说一个经典的单进程 和 多进程/多线程的操作系统,
我们可以看到在单进程系统中,只需要无脑的将进程串行排列好, CPU 会串行去执行任务,如果遇到进程1 阻塞的情况,其他进程也没有办法被 cpu 执行,那么进程2 ,进程3 ,进程4 就都要等待前面的进程完成执行完毕,才能到自己执行
可以看出单进程对于 CPU 的使用过于任性,浪费 CPU 的资源,演进到多进程/多线程操作系统的时候,就出现了调度器
上图中我们可以对比看到,在多进程/多线程的操作系统中,cpu 的时间片被分割的更加的小,对于 cpu 资源的利用率是大大的增加了,因为 cpu 可以在进程1阻塞的时候,切换去执行进程2
例如,当进程1 执行过程中,发生了阻塞,那么调度器就会就会将 cpu 切换到进程2 中进行执行,同理,进程2 阻塞的时候, cpu 就会被切换到进程 3 进行执行,当然,这就看是哪个进程先抢到 cpu 资源了
可以看到,调度器在这里的作用就是最大限度的利用上 CPU 的资源,管理进程在 CPU 上按照一定的的顺序执行任务,就好比一个优秀的管家可以合理安排好不同的员工在指定的时间上专注的处理某项事务
那么 golang 的调度器是不是也是和 linux 中的调度器有着想通之处呢?
来看看调度器在 golang 中的具体作用是干啥的
在 golang 中,调度器的实现简单来看实际上是由协程和线程按照一定的逻辑来组合起来的,其实也是扮演着一个协调和调度的作用,调度的对象是协程和线程,协程是需要被调度到线程中来运行的,这个动作就是调度器干的
- 通常用 G 来表示协程
- 用 M 来表示线程
正如是这样来实现调度器的:
我们可以看到,当每一个 M 想要从全局队列中取 G 出来执行的时候,是需要访问全局队列的锁,这是一把互斥锁,同一时间只能有 1 个 M 在访问
Golang 的调度器此处当然也能让多个 M 处理不同的 G,达到多进程/多线程 并发处理事项的目的
可我们知道,加锁,是会影响到我们系统的整体性能的,毕竟那么多 M 都在竞争这一把锁,势必同一时间没有抢到的锁的 M 就要等待了
为什么调度器会被淘汰掉?
看到上图,细心的我们可以发现,
所以,这个调度器缺点也是比较明显的:
第一,多个 M 都要并发的去获取全局队列中的 G ,会造成锁竞争 , 此处操作全局队列的情况有如下几种情况
- 创建 G
- 调度 G
- 销毁 G
第二, 线程 M 在执行 G 的过程中,如果 G 阻塞了,那么 M 也就阻塞了,这个时候,CPU 就需要切换到其他的 M 上执行 G,这个切换的过程也是对于 CPU 资源的浪费
正如人的大脑,同时处理多个事项,当 事项 1 未处理完毕,就去处理事项 2,那么需要重新理清思绪去执行,若这个时候又需要切换到 事项 1 的时候,就需要花更多的时间来回顾之前事项 1 处理的上下文了, 所以在工作中,没有特别必要,不要打扰别人
第三, 我们知道在 golang 中,一个 G 也是可以再创建 G 的,就叫 G1 吧,那么创建的这个 G1 就需要交给其他的 M 来进行执行了,因为当前的 M 正在执行 G,自己忙不过来,因此需要将 G1 交给 M1 执行
这也是一个很明显的问题
正如上述例子一样, 2 个人排查相关问题,但是信息和认知不一致,很明显是小猪可能是比较难排查出问题来的
就像 M 执行 G 新创建了 G1,但是是交给 M1 来执行的, M1 并不知道 G1 和 G 的关系,M1 执行起来就可能会出现问题,例如需要 G 的一些上下文,但是 M1 并不知情
因此,随着时间的推移,对于性能的要求是越来越高,当然是要想办法换一个与时俱进,需要符合时代潮流的管家了,自然就出现了一个新的调度器替代了原有的调度器
出现新的调度器,自然是解决了旧的调度器的缺点,并且还带来了一些新的属性和价值,具体的新调度器策略我们可以在下文中进行展示
为什么会出现协程
在来看另外一个问题,为什么会出现协程,自然是因为使用进程和线程不能够满足我们的某些需求了,此处的需求是指对于性能的要求,是对 CPU 利用效率的需求
上图中我们有说到,对于多进程/多线程并发的时候,我们有提高 CPU 的利用率,尽可能的利用好 CPU 的时间片,但是对于 CPU 从 进程/线程1 切换到去执行进程/线程 2 的过程中,是会产生消耗的,但是这个消耗很难避免
那么我们知道 CPU 其实执行的是线程,那么如果 1 个线程里面还可以分成多个程序进行并发岂不是可以大大的提高我们当前线程的使用效率?
我们从 C/C++ 中知道,咱们的一个32位系统的机器,进程实际上是开辟了一个 4G 的虚拟空间,具体 4G 虚拟空间都包含了什么,我们可以简单的看看这个图,本次不在此细聊
那线程大概也是需要 4M 的空间,那么我们在一定程度上大量的开辟进程或者线程,必然会带来系统中 内存占用高,调度 CPU 切换的消耗高 的问题
后来,我们知道线程实际上是分为内核态和用户态的
当然,用户态的线程是依赖于内核态线程的,用户态中需要执行的内容,是需要放在内核态线程上进行执行的,另外, CPU 只知道有内核态线程的存在,意味着,CPU 只认内核态线程
此处说的内核态,和用户态,其实就是对应到我们说的 M 和 G
- 内核态线程 – 线程
- 用户态线程 – 协程
协程不会陷入到内核态中,因此在 M 不变的情况下,切换 G 就是非常轻快的了,协程简要有如下特点:
- 占用内存空间小,只占用 几 kb ,比起进程,线程来说,真的是很小了
- 调度灵活,他是处于用户态进行调度的
根据协程和线程处于的用户态和内核态,我们可以看到调度的机制是不一样的,
内核态中的线程,实际上是抢占式的,是又 CPU 调度的
用户态中的线程,即协程,是由用户态调度的,此处的用户态调度,就可以理解是一个队列了,只能一个一个的去执行了,一个协程执行完毕之后,让出 CPU ,才会执行下一个协程
好比我们代码中,多个协程,其中 1 个协程 panic 了,如何不捕获的话,是不是整个程序都崩溃了
对于 CPU 只认内核态线程这一点,咱理解起来就想到与一个公司的老板,只认每个产品线上的总监一样,你这个主管后面不管有多人少人在干活,老板只认为是你这个主管在干活
当然一个公司也不仅仅只有 1 个老板,就像计算机系统里面也会有多个 CPU ,但是道理是一样的
如何理解 GMP 模型
GMP 分别表示 协程 goroutine,线程 thread,处理器 processor
他们三组成了新的调度器,他们三者的关系这样的
咱们从图中可以知道有全局队列,本地队列
全局队列还是和之前一样,从里面里面 G 的创建,调度,销毁 都是需要访问互斥锁的
P 的本地队列 自己维护了一个 G 列表,最长是 256 个,那 P 的个数一般是 GOMAXPROCS 个,如果本地的队列满了,那么 P 会将队列中的一半给到全局队列中
从本地队列中取 G 是不需要加锁的,直接取即可,且如果队列中的 G 又创建了 G1 ,那么这个 G1 也是会被优先加入到当前本地队列的
此处我们可以看到 M 是和 P 进行对应了,当 M 需要运行 G 的时候,就需要先找到一个合适的 P ,从 P 中获取 G, 如果 P 为空,那么 M 就会从全局队列中获取一批 G 放到 P 的队列中
或者是 M 也会从其他的 P 的队列中偷一半的 G 到当前 P 的队列中
从这里我们可以知道,新的调度器,已经解决了旧的调度器的一部分问题了(不需要每次都去找全局队列)
那么 P 是啥时候创建,创建多少个?M 又是啥时候创建的,创建多少个呢? P 和 M 在数量上有必然联系吗?
P 是在程序启动的时候,读取环境变量中 GOMAXPROC ,来创建具体 P 的个数
M 的创建实际上是,若 P 中有很多任务 G ,如果有空闲的 M,那么 P 就会找任意空闲 M 来进行处理,如果没有空闲的 M ,那么调度器就会去创建 M 来执行 P 中的 任务
那么新的调度器还有哪些优势呢?
第一
提高了线程的复用率,如果当前线程执行完当前 P 的任务之后,当前的 M 会尝试去偷其他 P 里面的 G 来进行执行,这样我们就尽可能的避免了线程的创建,销毁带来的开销
第二
如果当前的 M 在执行 G 的时候,出现了阻塞,那么 M 也会很懂事的让出当前的 P,让其他 M 来执行 P 中的任务,当前的 M 就继续处理当前的 G
第三
上述我们说到当前 M 会去从其他 P 的队列中偷 G,这个是在当前 M 对应的 P 中没有 G 的时候,优先去做的事情, 如果其他的 P 也没有 G 的时候,当前 M 才会去全局队列中拿
从这里就可以开始,新的调度器,已经是在大大的弱化了全局队列的作用
本次先聊到这里,相信你对 GMP 的基本理论也有一些了解了吧
感谢阅读,欢迎交流,点个赞,关注一波 再走吧
可以进入地址进行体验和学习:https://xxetb.xet.tech/s/3lucCI
相关文章:
![](https://img-blog.csdnimg.cn/img_convert/f6dfcabed87227900fc14fee105b7279.png)
谈谈对 GMP 的简单认识
犹记得最开始学习 golang 的时候,大佬们分享 GMP 模型的时候,总感觉云里雾里,听了半天,并没有一个很清晰的概念,不知 xmd 是否会有这样的体会 虽然 golang 入门很简单,但是对于理解 golang 的设计思想和原…...
![](https://www.ngui.cc/images/no-images.jpg)
Java正则表达式系列--从字符串中提取字符串或数字
原文网址:Java正则表达式系列--从字符串中提取字符串或数字_IT利刃出鞘的博客-CSDN博客 简介 本文用示例介绍Java如何使用正则表达式从字符串中提取想要的内容(字符串或者数字等)。 例1:提取一次不同内容 需求 从字符串中找到…...
![](https://img-blog.csdnimg.cn/45e87cbd4f3e4fa29dfc5b630c1cafc2.png)
机器学习实战之模型的解释性:Scikit-Learn的SHAP和LIME库
概要 机器学习模型的“黑箱”困境 机器学习模型的崛起让我们惊叹不已!不论是预测房价、识别图片中的猫狗,还是推荐给你喜欢的音乐,这些模型都表现得非常出色。但是,有没有想过,这些模型到底是如何做出这些决策的呢&a…...
![](https://img-blog.csdnimg.cn/img_convert/43c685c0a49a9abd6ca66c3d73a5b1b9.png)
Go 语言进阶与依赖管理 | 青训营
Powered by:NEFU AB-IN 文章目录 Go 语言进阶与依赖管理 | 青训营 语言进阶依赖管理测试 Go 语言进阶与依赖管理 | 青训营 GO语言工程实践课后作业:实现思路、代码以及路径记录 语言进阶 Go可以充分发挥多核优势,高效运行 Goroutine是Go语言中的协程…...
![](https://www.ngui.cc/images/no-images.jpg)
hyperf 十三 视图
教程:Hyperf composer地址:hyperf/view - Packagist 本次测试使用twig twig composedr地址:twig/twig - Packagist twig 文档地址:Home - Twig - The flexible, fast, and secure PHP template engine 一、安装 composer re…...
![](https://www.ngui.cc/images/no-images.jpg)
请你说说前端图形图像的框架
前端图形图像方面有许多强大的框架和库,使得开发者能够更容易地创建丰富的视觉效果和复杂的图形应用。下面列举了一些主要的框架和库: 1. Three.js Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它创建各种三维场景,包括了…...
![](https://img-blog.csdnimg.cn/a76b2cb8ead94c4cbcb51fe139f41c35.png)
C++数据结构学习——栈
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、栈二、C语言实现1.声明代码2.实现增删查改代码3.测试代码 总结 前言 栈(Stack)是计算机科学中一种常见的数据结构,它是…...
![](https://img-blog.csdnimg.cn/e13f2cca67b44a8da551d87ca00d434f.png)
【C++笔记】C++之类与对象(下)
【C笔记】C之类与对象(下) 1、再看构造函数1.1、构造函数的初始化列表1.2、C支持单参数的构造函数的隐式类型转换1.3、匿名对象 2、Static成员2.1、为什么要有静态成员变量?2.2、一个类的静态成员变量属于这个类的所有对象2.3、静态成员函数 3、友元3.1、…...
![](https://www.ngui.cc/images/no-images.jpg)
管理类联考——英语——实战篇——大作文——图表——动态图表——整体效果
动态图表模板 What is clearly presented in the above 图表类型 is that dramatic changes have taken place in 主题词1 from 年份1 to 年份2.During the period, there was a marked jump from 数字1 to 数字2 in 事物1,while that of 事物2 declined significantly from 数…...
![](https://img-blog.csdnimg.cn/4a0338b7cdaa47d794cc160c3d15e663.png)
threejs纹理加载三(视频加载)
threejs中除了能把图片作为纹理进行几何体贴图以外,还可以把视频作为纹理进行贴图设置。纹理的类型有很多,我们可以用不同的加载器来加载,而对于视频作为纹理,我们需要用到今天的主角:VideoTexture。我们先看效果&…...
![](https://img-blog.csdnimg.cn/img_convert/ebc47c6e601408dafbfb4e7a0be4f5f5.png)
VUE笔记(三)vue的语法
一、计算属性 1、计算属性的概念 计算属性是依赖于源数据(data或者属性中的数据),在元数据的基础上进行逻辑运算后得到的新的数据,计算属性要依赖于源数据,源数据数据变化计算属性也会变化 2、计算属性的语法 在vue2中使用computed这个选…...
![](https://img-blog.csdnimg.cn/37b8fa718b1349109e9b9fbfbe5a34c7.png)
探讨uniapp的路由与页面生命周期问题
1 首先我们引入页面路由 2 页面生命周期函数 onLoad() {console.log(页面加载)},onShow() {console.log(页面显示)},onReady(){console.log(页面初次显示)},onHide() {console.log(页面隐藏)},onUnload() {console.log(页面卸载)},onBackPress(){console.log(页面返回)}3 页面…...
![](https://img-blog.csdnimg.cn/c39fdaae525641f48070dd34688360e1.png)
咸鱼之王俱乐部网站开发
我的俱乐部 最新兑换码 *注意区分大小写,中间不能有空格! APP666 HAPPY666 QQ888 QQXY888 vip666 VIP666 XY888 app666 bdvip666 douyin666 douyin777 douyin888 happy666 huhushengwei888 taptap666 周活动 宝箱周 宝箱说明 1.木质宝箱开启1个…...
![](https://www.ngui.cc/images/no-images.jpg)
Electron+Vue3+TS 打包exe客户端
Electron Vue3 TS 实战 - 掘金 如果报错loaderContext.getOptions is not a function ts-loader版本不一致导致的问题。 解决方案:npm install ts-loader8.0.0 --save...
![](https://img-blog.csdnimg.cn/b46a9d7ac7c64512924455b6b3175c37.png)
vue3范围选择组件封装
个人项目地址: SubTopH前端开发个人站 (自己开发的前端功能和UI组件,一些有趣的小功能,感兴趣的伙伴可以访问,欢迎提出更好的想法,私信沟通,网站属于静态页面) SubTopH前端开发个人站…...
![](https://www.ngui.cc/images/no-images.jpg)
能被整除的数(容斥原理)
思路: (1)需求:求对于1~n中至少能被p1~pm至少1个整除的数的个数,由于都是质数,彼此互质,不需要进行质因子分解,根据容斥原理, res n/p1 n/p2 ... n/pm - n /(p1p2) -…...
![](https://img-blog.csdnimg.cn/0a4277007c32428489eb45c6f5b9ba9e.png)
Modbus转Profinet网关与流量变送器兼容转ModbusTCP协议博图配置
首先,我们需要明确电磁流量计的通信协议是Modbus,而西门子1200PLC的通信协议是Profinet。这两种协议在功能和特性上存在一定的差异,因此需要使用兴达易控Modbus转Profinet网关设备进行转换。兴达易控的XD-MDPN100是Profinet转ModbusTCP的网关…...
![](https://img-blog.csdnimg.cn/3484e74afa6549e496088f0992298077.png#pic_center)
HLS实现CORDIC算法计算正余弦并上板验证
硬件:ZYNQ7010 软件:MATLAB 2019b、Vivado 2017.4、HLS 2017.4、System Generator 2017.4 1、CORDIC算法计算正余弦 CORDIC算法详细分析网上有很多资料,它的原理是用一系列旋转去逼近目标角度,这一系列旋转的角度为 θ a r c t…...
![](https://img-blog.csdnimg.cn/bd4b43a626ec415c8ac273ec45abd9cd.png)
高阶数据结构并查集
目录: 并查集的概念代码实现 LeetCode例题 并查集的概念 将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元元素集合,然后按一定的规律将归于同一组元素的集合合并。在此过程中反复遇到查询某一个元素属于那个集合的运算…...
![](https://img-blog.csdnimg.cn/f2f93842c432457c8228c496ceea8c22.png)
WSL2连接不了外网怎么办?
某天忽然WLAN变成地球图标,上不了Internet,搞了半天网络适配器,仍然不行。回忆之前做过的操作,曾经运行过ZoogVPN,试着启动并连接,然后退出,WLAN神奇地恢复了连接,可以上Internet了。…...
![](https://www.ngui.cc/images/no-images.jpg)
【C/C++】探索内存对齐的奥秘与优势
目录 一,前言 二,什么是内存对齐? 三,内存对齐的原理 四,内存对齐的优势 五,如何实现内存对齐?(看这节就行) 1.使用 #pragma pack 来实现内存对齐的示例 七&#…...
![](https://www.ngui.cc/images/no-images.jpg)
leetcode分类刷题:滑动窗口(二、重复元素类型)
1、连续子数组、连续子串问题通常需要滑动窗口来求解,本篇文章对应的“二、重复元素类型”在此基础上对连续子数组、连续子串中重复元素个数、种类进行考察,此时,需要使用和维护哈希表进行左右指针的移动,因此这类题目对应的解法为…...
![](https://img-blog.csdnimg.cn/9cd1544f884c4665a1cc3b1d8861338c.png)
MySQL—buffer pool
一、buffer pool的介绍 Buffer pool是什么 一个内存区域,为了提⾼数据库的性能,数据库操作数据的时候,把硬盘上的数据加载到buffer pool,不直接和硬盘打交道,操作的是 buffer pool的数据,数据库的增删改查…...
![](https://www.ngui.cc/images/no-images.jpg)
《C和指针》笔记8: 枚举类型
枚举 (enumerated)类型就是指它的值为符号常量而不是字面值的类型,它们以下面这种形式声明: enum Jar_Type { CUP, PINT, QUART, HALF_GALLON, GALLON };这条语句声明了一个类型,称为Jar_Type。这种类型的变量按下列方式声明: e…...
![](https://img-blog.csdnimg.cn/f84f55b244044817a84be4552036dabe.png)
Python爬虫框架之Selenium库入门:用Python实现网页自动化测试详解
概要 是否还在为网页测试而烦恼?是否还在为重复的点击、等待而劳累?试试强大的Selenium!让你的网页自动化测试变得轻松有趣! 一、Selenium库到底是什么? Selenium 是一个强大的自动化测试工具,它可以让你直…...
![](https://www.ngui.cc/images/no-images.jpg)
docker swarm 部署服务网络问题
docker swarm 服务部署问题 docker swarm 部署服务时可能会出现,启动服务特别慢的情况,甚至一个service 启动后,容器会长时间处于 preparing 状态,直到 状态切换成 running 状态后,才会启动下一个service。然后查询资…...
![](https://www.ngui.cc/images/no-images.jpg)
1.00001git源码clone后进行编译(带调试)
– 新建用户 useradd postgres passwd postgres – 用户加入sude组 先cd到/etc/sudoers目录下 由于sudoers文件为只读权限,所以需要添加写入权限,chmod uw sudoers vim sudoers 找到root ALL (ALL) ALL这一行,在下一行加入username ALL (A…...
![](https://img-blog.csdnimg.cn/31bcaf9068074d84ad97987384a02a2c.png)
使用StorageClass动态创建pv
rook-ceph安装部署到位后,就可以开始来尝试使用StorageClass来动态创建pv了。 有状态的中间件在kubernetes上落地基本上都会用到StorageClass来动态创建pv(对于云上应用没有那么多烦恼,云硬盘很好用,但是对于自己学习和练习来说还…...
![](https://img-blog.csdnimg.cn/9f2633f8c30845caa3d06fda8146f357.png)
数据结构(Java实现)-ArrayList与顺序表
什么是List List是一个接口,继承自Collection。 List的使用 List是个接口,并不能直接用来实例化。 如果要使用,必须去实例化List的实现类。在集合框架中,ArrayList和LinkedList都实现了List接口。 线性表 线性表(lin…...
![](https://img-blog.csdnimg.cn/094aba52a8da48c9857a5a38e9517ad5.png)
性能优化维度
CPU 首先检查 cpu,cpu 使用率要提升而不是降低。其次CPU 空闲并不一定是没事做,也有可能是锁或者外部资源瓶颈。常用top、vmstat命令查看信息。 vmstat 命令: top: 命令 IO iostat 命令: Memory free 命令: 温馨提示:…...
![](https://img-blog.csdnimg.cn/20190120110349997.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwMDM2NzU0,size_16,color_FFFFFF,t_70)
美容院门户网站开发/百度关键词查询
Android Studio 3.0 之后Tools没有Android选项,想打开monitor查看文件就不行,解决方法: 这样即可找到虚拟机或者真机的文件。 如果是真机的文件,一定要记得小心哦。...
![](https://img-blog.csdnimg.cn/img_convert/00857bb40ba09a157c5e89aa432f02f2.png)
ps个人主页设计/百度搜索引擎优化方式
一、在canvas画布中如何加载图片---用drawImage( )方法drawImage用法的三种情况:1、在画布指定位置定义图像ctx.drawImage(img,x,y);注:此时画布上显示的图片大小是图片的默认大小2、在画布上定位图像,并规定图像的宽度和高度:ctx…...
![](/images/no-images.jpg)
杭州专业网站设计制作/广告推广语
性能优化方案--之一方案计划 Oracle优化 Oracle是咱们存储软件,他自身的优化是决定咱们系统软件性能的根本。 相关需要优化的配置: PGA:适当大小,保证SQL高速缓存命中能在99%以上。 SGA:调整适当增加共享内存池大小&am…...
![](https://img-blog.csdnimg.cn/img_convert/5e5615532b4cb87eed66c29cbb8332ad.png)
长沙工程建设管理中心网站/seo专业实战培训
从今年开始除了5G之外,智能手机还迎来了几个重要更新,一个就是UFS 3.1,一个WiFi 6,还有一个就是LPDDR5,也就是第五代低功耗内存版本,手机内存性能提升的同时,大小容量也在不断提升,已…...
做网站那个公司/免费seo网站推荐一下
日期内核版本架构作者GitHubCSDN2016-05-29Linux-4.5X86 & armgatiemeLinuxDeviceDriversLinux进程管理与调度-之-进程的创建 前言 Linux下有3个特殊的进程,idle进程(PID0), init进程(PID1)和kthreadd(PID2) * idle进程由系统自动创建, 运行在内核态 idle进…...
![](/images/no-images.jpg)
建盏产业品牌/百度seo排名优化排行
刚接触mongodb不久。踩到许多坑,记录下一些基于spring-data-mongodb的东西吧 首先。应该了解下什么情况下使用mongodb,什么情况下用mysql: 业务需要事物,使用mysql,因为mongodb不支持事物数据量大,但是数据…...