GMP调度模型
Golang GMP调度模型
Go 语言的Goroutine其实概念和协程是一致的,我们可以称之为有go特色的协程
为了解决多线程调度器的问题,Go 开发者 Dmitry Vyokov 在已有 G、M 的基础上,引入了 P 处理器,由此产生了当前 Go 中经典的 GMP 调度模型。
P:Processor的缩写,代表一个虚拟的处理器,它维护一个局部的可运行的 G 队列,可以通过 CAS 的方式无锁访问,工作线程 M 优先使用自己的局部运行队列中的 G,只有必要时才会去访问全局运行队列,这大大减少了锁冲突,提高了大量 G 的并发性。每个 G 要想真正运行起来,首先需要被分配一个 P。
如图 1.5 所示,是当前 Go 采用的 GMP 调度模型。可运行的 G 是通过处理器 P 和线程 M 绑定起来的,M 的执行是由操作系统调度器将 M 分配到 CPU 上实现的,Go 运行时调度器负责调度 G 到 M 上执行,主要在用户态运行,跟操作系统调度器在内核态运行相对应。
M 是最重要的结构是一个线程的概念系统会为其分配Cpu资源,用来串联内核态和用户态,Goroutinue的具体代码与M绑定 ...
想要写好Go并发不得不掌握的数据结构
想要写好Go并发不得不掌握的数据结构Mutext018 年,Go 开发者将 fast path 和 slow path 拆成独立的方法,以便内联,提高性能。
2019 年也有一个 Mutex 的优化,虽然没有对 Mutex 做修改,但是,对于 Mutex 唤醒后持有锁的那个 waiter,调度器可以有更高的优先级去执行,这已经是很细致的性能优化了。为了避免代码过多,这里只列出当前的 Mutex 实现。
想要理解当前的 Mutex,我们需要好好泡一杯茶,仔细地品一品了。当然,现在的 Mutex 代码已经复杂得接近不可读的状态了,而且代码也非常长,删减后占了几乎三页纸。但是,作为第一个要详细介绍的同步原语,我还是希望能更清楚地剖析 Mutex 的实现,向你展示它的演化和为了一个貌似很小的 feature 不得不将代码变得非常复杂的原因。
当然,你也可以暂时略过这一段,以后慢慢品,只需要记住,Mutex 绝不容忍一个 goroutine 被落下,永远没有机会获取锁。不抛弃不放弃是它的宗旨,而且它也尽可能地让等待较长的 goroutine 更有机会获取到锁。
1234567891011121 ...
设计模式的一些使用原则
设计模式的一些使用原则
之前把23种设计模式结合golang代码总结了一下,但这23种设计模式相当于武功招式,只掌握了武功招式没有内功心法是没办法发挥其作用,你只会盲目的去套用招式这往往会得到相反的效果,我们经常看到过度设计导致代码不但复杂而且性能低下。这一篇文章就总结一下为什么要使用23种设计模式。
用好设计模式首先要了解面向对象:
面向对象设计封装(Encapsulation)封装也叫作信息隐藏或者数据访问保护。类通过暴露有限的访问接口,授权外部仅能通过类提供的方式(或者叫函数)来访问内部信息或者数据。
封装也叫作信息隐藏或者数据访问保护。类通过暴露有限的访问接口,授权外部仅能通过类提供的方式来访问内部信息或者数据。它需要编程语言提供权限访问控制语法来支持,例如 Java 中的 private、protected、public 关键字。封装特性存在的意义,一方面是保护数据不被随意修改,提高代码的可维护性;另一方面是仅暴露有限的必要接口,提高类的易用性。
抽象(Abstraction)抽象是从具体事物中提取共性,形成更高层次的概念。
计算机科学中的抽象是通过隐藏细节,简化复杂系统的 ...
结合Golang聊聊23种设计模式---行为型(3)
结合Golang聊聊23种设计模式—行为型(3)责任链模式责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。
责任链模式的英文翻译是 Chain Of Responsibility Design Pattern。
在 GoF 的《设计模式》中,它是这么定义的:Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
翻译成中文就是:将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。
这么说比较抽象,我用更加容易理解的话来进一步解读一下。在 ...
结合Golang聊聊23种设计模式---行为型(2)
结合Golang聊聊23种设计模式—行为型(2)策略模式策略模式,英文全称是 Strategy Design Pattern。在 GoF 的《设计模式》一书中,它是这样定义的:
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
翻译成中文就是:定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。
我们知道,工厂模式是解耦对象的创建和使用,观察者模式是解耦观察者和被观察者。策略模式跟两者类似,也能起到解耦的作用,不过,它解耦的是策略的定义、创建、使用这三部分。
为什么要使用策略模式策略模式是一种行为设计模式, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。
我们可以利用策略模式来移除 if-else ...
结合Golang聊聊23种设计模式---行为型(1)
结合Golang聊聊23种设计模式—行为型(1)
我们常把 23 种经典的设计模式分为三类:创建型、结构型、行为型。前面我们已经学习了创建型和结构型,从今天起,我们开始学习行为型设计模式。我们知道,创建型设计模式主要解决“对象的创建”问题,结构型设计模式主要解决“类或对象的组合或组装”问题,那行为型设计模式主要解决的就是“类或对象之间的交互”问题。
行为型设计模式比较多,有 11 个,几乎占了 23 种经典设计模式的一半。它们分别是:观察者模式、模板模式、策略模式、职责链模式、状态模式、迭代器模式、访问者模式、备忘录模式、命令模式、解释器模式、中介模式。
观察者模式观察者模式(Observer Design Pattern)也被称为发布订阅模式(Publish-Subscribe Design Pattern)。在 GoF 的《设计模式》一书中,它的定义是这样的:Define a one-to-many dependency between objects so that when one object changes state, all its dependents are ...
结合Golang聊聊23种设计模式---结构型(2)
结合Golang聊聊23种设计模式—结构型(2)适配器模式适配器模式的英文翻译是 Adapter Design Pattern。顾名思义,这个模式就是用来做适配的
为什么要使用适配器模式适配器模式可以将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。对于这个模式,有一个经常被拿来解释它的例子,就是 USB 转接头充当适配器,把两种不兼容的接口,通过转接变得可以一起工作。
代码示例这里有一段客户端代码, 用于接收一个对象 (Lightning 接口) 的部分功能, 不过我们还有另一个名为 adaptee 的对象 (Windows 笔记本), 可通过不同的接口 (USB 接口) 实现相同的功能
这就是适配器模式发挥作用的场景。 我们可以创建这样一个名为 adapter 的结构体:
遵循符合客户端期望的相同接口 (Lightning 接口)。
可以适合被适配对象的方式对来自客户端的请求进行 “翻译”。 适配器能够接受来自 Lightning 连接器的信息, 并将其转换成 USB 格式的信号, 同时将信号传递给 Windows 笔记本的 USB 接口。
...
结合Golang聊聊23种设计模式---结构型(1)
结合Golang聊聊23种设计模式—结构型(1)结构型模式主要总结了一些类或对象组合在一起的经典结构,这些经典的结构可以解决特定应用场景的问题。结构型模式包括:代理模式、桥接模式、装饰器模式、适配器模式、门面模式、组合模式、享元模式。
代理模式代理模式(Proxy Design Pattern)它在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。
为什么要使用代理模式第一,防止框架如监控、统计、鉴权、限流、事务、幂等、日志,缓存等代码侵入到业务代码中,跟业务代码高度耦合。如果未来需要替换这个框架,那替换的成本会比较大。
第二,框架代码跟业务代码无关,本就不应该放到一个类中。业务类最好职责更加单一,只聚焦业务处理。
代理类负责在业务代码执行前后附加其他逻辑代码,并通过委托的方式调用原始类来执行业务代码。具体的代码实现如下所示:
Nginx 这样的 Web 服务器可充当应用程序服务器的代理:
提供了对应用程序服务器的受控访问权限。
可限制速度。
可缓存请求。
server.go: 主体12345package maintype server interfac ...
结合Golang聊聊23种设计模式---创建型
结合Golang聊聊23种设计模式—创建型
将不要过度设计也不要随意堆砌烂代码写在前面设计模式要干的事情就是解耦,也就是利用更好的代码结构将一大坨代码拆分成职责更单一的小类,让其满足高内聚低耦合等特性。创建型模式是将创建和使用代码解耦,结构型模式是将不同的功能代码解耦,行为型模式是将不同的行为代码解耦。而解耦的主要目的是应对代码的复杂性。设计模式就是为了解决复杂代码问题而产生的。因此,对于复杂代码,比如项目代码量多、开发周期长、参与开发的人员多,我们前期要多花点时间在设计上,越是复杂代码,花在设计上的时间就要越多。 不仅如此,每次提交的代码,都要保证代码质量,都要经过足够的思考和精心的设计,这样才能避免烂代码效应(每次提交的代码质量都不是太好,最终积累起来整个项目的质量就变得很差)。相反,如果你参与的只是一个简单的项目,代码量不多,开发人员也不多,那简单的问题用简单的解决方案就好,不要引入过于复杂的设计模式,将简单问题复杂化。
单例模式为什么要使用单例?单例设计模式(Singleton Design Pattern)理解起来非常简单。一个类只允许创建一个对象(或者实例),那这个类就是 ...
高性能 Golang 并发包 -- ant
高性能 Golang 并发包 – ant
接触了很多比较热的并发包和小工具,比如之前我写到的Tunny,Machinery等等,我觉得设计的最好的还是 ant,当然Tunny更轻便,Machinery主打分布式并发处理各自有自身优势,但如果你要选一个单服务进行的生产消费的并发处理包,那一定是 ant。
ant 把很多性能优化都做到了很好,在高并发种容易出现的内存泄露,GC压力等问题都在设计上进行了很好的规避,让性能做到起飞。
下面我通过源码来和大家一起学习下它的一些精彩设计。
程序流程:ant 的主体是pool结构 ,pool结构管理着worker队列,worker是执行任务的最小单位。
生产者不断提交任务给pool,pool 进行任务的调度处理。
下面是整个包工作的流程图:
主体架构整个包设计的主体分为三层最上层是pool 接够,中层是queue结构,底层是worker结构。
处理任务的最小单位是worker 结构,queue其实就一个worker的队列,负责worker的调度和清理等工作,pool是最上层的结构也就是我们接触到的使用结构,pool主要负责并发数量控制,task发 ...