Go语言
文章平均质量分 85
金戈鐡馬
这个作者很懒,什么都没留下…
展开
-
Golang 编写 Tcp 服务器
Golang 作为广泛用于服务端和云计算领域的编程语言,tcp socket 是其中至关重要的功能。早期的 Tomcat/Apache 服务器使用的是阻塞 IO 模型。它使用一个线程处理一个连接,在没有收到新数据时监听线程处于阻塞状态,直到数据就绪后线程被唤醒。因为阻塞 IO 模型需要开启大量线程并且频繁地进行上下文切换,所以效率很差。IO 多路复用技术为了解决上述问题采用了一个线程监听多路连接的方案。一个线程持有多个连接并阻塞等待,当其中某个连接可读写时线程被唤醒进行处理。原创 2023-04-23 00:30:00 · 821 阅读 · 0 评论 -
Golang中的汇编详解
我们知道 Go 语言的三位领导者中有两位来自 Plan 9 项目,这直接导致了 Go 语言的汇编采用了比较有个性的 Plan 9 风格。不过,我们不能因咽废食而放弃无所不能的汇编。不同体系结构的 CPU,其内部寄存器的数量、种类以及名称可能大不相同,这里我们只介绍 AMD64 的寄存器。AMD64 有 20 多个可以直接在汇编代码中使用的寄存器,其中有几个寄存器在操作系统代码中才会见到,而应用层代码一般只会用到如下三类寄存器。原创 2023-05-12 08:00:00 · 906 阅读 · 0 评论 -
浅析Golang中的channel
Channel 是 Golang 在语言级别提供的 goroutine 之间的通信方式,可以使用 channel 在两个或多个 goroutine 之间传递消息。Channel 是进程内的通信方式,因此通过 channel 传递对象的过程和调用函数时的参数传递行为比较一致,比如也可以传递指针等。使用通道发送和接收所需的共享资源,可以在 goroutine 之间消除竞争条件。原创 2023-05-11 22:43:41 · 427 阅读 · 1 评论 -
深入Golang之sync.Pool详解
通过以上的解读,我们可以看到,Get方法并不会对获取到的对象值做任何的保证,因为放入本地池中的值有可能会在任何时候被删除,但是不通知调用者。放入共享池中的值有可能被其他的goroutine偷走。所以对象池比较适合用来存储一些临时切状态无关的数据,但是不适合用来存储数据库连接的实例,因为存入对象池重的值有可能会在垃圾回收时被删除掉,这违反了数据库连接池建立的初衷。根据上面的说法,Golang的对象池严格意义上来说是一个临时的对象池,适用于储存一些会在goroutine间分享的临时对象。原创 2023-05-01 00:17:24 · 984 阅读 · 3 评论 -
golang中panic和recover的使用规则
在golang当中不存在tye ... catch 异常处理逻辑。在golang当中使用defer, panic和recover来控制程序执行流程,借此来达到处理异常的目的。Panic是一个可以停止程序执行流程的内置函数。假设当前F函数当中某处代码触发panic函数,则F函数停止后面代码的执行,转而执行F函数内部的defer函数(如果已经声明了defer函数的话...),然后结束F函数,将当前处理权转给F的调用函数。对于F的调用方M来说,。这一点很重要,因为调用panic函数结束是没有返回值的。原创 2023-05-05 00:15:00 · 183 阅读 · 0 评论 -
golang中defer的使用规则
在golang当中,defer代码块会在函数调用链表中增加一个函数调用。这个函数调用不是普通的函数调用,而是会在函数正常返回,也就是return之后添加一个函数调用。因此,defer通常用来释放函数内部变量。原创 2023-05-04 00:15:00 · 143 阅读 · 0 评论 -
深入Golang调度器之GMP模型
随着服务器硬件迭代升级,配置也越来越高。为充分利用服务器资源,并发编程也变的越来越重要。在开始之前,需要了解一下并发(concurrency)和并行(parallesim)的区别。并发:逻辑上具有处理多个同时性任务的能力。并行:物理上同一时刻执行多个并发任务。通常所说的并发编程,也就是说它允许多个任务同时执行,但实际上并不一定在同一时刻被执行。在单核处理器上,通过多线程共享CPU时间片串行执行(并发非并行)。而并行则依赖于多核处理器等物理资源,让多个任务可以实现并行执行(并发且并行)。原创 2023-05-03 00:15:00 · 358 阅读 · 3 评论 -
golang内存分配
这个函数先计算出传入参数的大小,然后调用mallocgc函数,这个函数三个参数,第一个参数是对象类型大小,第二个参数是对象类型,第三个参数是malloc的标志位,这个标志位有两位,一个标志位代表GC不需要扫描这个对象,另一个标志位说明这个对象并不是空内存。这两个链表的机制是这样的,我new一个对象的时候,从nonempty中获取这个空间,放到empty链表中去,当我free一个对象的时候,从empty链表中还原到nonempty链表中去。其中的m,p,g的信息需要对下面这个图有印象。原创 2023-05-02 00:15:00 · 183 阅读 · 0 评论 -
golang string和[]byte的对比
为啥string和[]byte类型转换需要一定的代价?为啥内置函数copy会有一种特殊情况?string和[]byte,底层都是数组,但为什么[]byte比string灵活,拼接性能也更高(今天看了源码探究了一下。原创 2023-05-01 00:15:00 · 389 阅读 · 0 评论 -
Golang实现 Redis 协议解析器
Redis 自 2.0 版本起使用了统一的协议 RESP (REdis Serialization Protocol),该协议易于实现,计算机可以高效的进行解析且易于被人类读懂。RESP 以行作为单位,客户端和服务器发送的命令或数据一律以 \r\n (CRLF)作为换行符。标准库可以将从 reader 读到的数据缓存到 buffer 中,直至遇到分隔符或读取完毕后返回,所以我们使用。,我们说 Go 语言的 string 是二进制安全的,而 C 语言字符串不是二进制安全的。命令本身将作为第一个参数,如。原创 2023-04-29 00:15:00 · 211 阅读 · 0 评论 -
Golang中使用跳表实现 SortedSet
实现ZRange命令最简单的数据结构是有序链表:在有序链表上实现命令需要进行end次查询, 即时间复杂度为O(n)跳表的优化思路是添加上层链表,上层链表中会跳过一些节点。如图所示:在有两层的跳表中,搜索的时间复杂度降低为了O(n / 2)。以此类推在有 log2(n) 层的跳表中,搜索元素的时间复杂度为O(log n)。// 对外的元素抽象Element // 元素的名称和 scorebackward *Node // 后向指针。原创 2023-04-28 00:30:00 · 183 阅读 · 0 评论 -
Golang实现 pipeline 模式的 redis 客户端
另一个方面,tcp 协议会保证数据流的有序性,同一个 tcp 连接上先发送的请求服务端先接收,先回复的响应客户端先收到。这种在服务端未响应时客户端继续向服务端发送请求的模式称为 Pipeline 模式。pipeline 模式的 redis 客户端需要有两个后台协程程负责 tcp 通信,调用方通过 channel 向后台协程发送指令,并阻塞等待直到收到响应,这是一个典型的异步编程模式。通常 TCP 客户端的通信模式都是阻塞式的:客户端发送请求 -> 等待服务端响应 -> 发送下一个请求。原创 2023-04-27 00:15:00 · 515 阅读 · 0 评论 -
Golang实现内存数据库
memcached hashtable 的渐进式 Rehash 策略使主线程和rehash线程之间的 data race 限制在哈希槽内,最小化rehash操作对读写操作的影响,这是最理想的实现方式。本文采用 golang 社区广泛使用的分段锁策略。解决方法是所有协程都按照相同顺序加锁,若两个协程都想获得键a和键b的锁,那么必须先获取键a的锁后获取键b的锁,这样就可以避免循环等待。在锁定多个key时需要注意,若协程A持有键a的锁试图获得键b的锁,此时协程B持有键b的锁试图获得键a的锁则会形成死锁。原创 2023-04-26 00:30:00 · 619 阅读 · 1 评论 -
Golang 实现集群与一致性 Hash
单台服务器的CPU和内存等资源总是有限的,随着数据量和访问量的增加单台服务器很容易遇到瓶颈。利用多台机器建立分布式系统,分工处理是提高系统容量和吞吐量的常用方法。使用更多机器来提高系统容量的方式称为系统横向扩容。与之相对的,提高单台机器性能被称为纵向扩容。由于无法在单台机器上无限提高硬件配置且硬件价格与性能的关系并非线性的,所以建立分布式系统进行横向扩容是更为经济实用的选择。我们采用一致性 hash 算法 key 分散到不同的服务器,客户端可以连接到服务集群中任意一个节点。原创 2023-04-25 00:30:00 · 382 阅读 · 1 评论 -
Golang中使用GeoHash 搜索附近的人
搜索附近的POI是一个非常常见的功能,它的技术难点在于地理位置是二维的(经纬度)而我们常用的索引(无论是B树、红黑树还是跳表)都是一维的。GeoHash 算法的本质就是将二维的经纬度转换为一维的表示。本文核心实现代码可以在中找到。也可以下载来亲自体验。兴趣点(Point Of Intererst, POI): 在电子地图中我们关心的各种地点被称为POI, 比如餐厅、超市、写字楼。POI 通常包含名称、经纬度、描述等信息。在搜索附近的人时,你也可以把附近的用户称为POI。原创 2023-04-24 00:30:00 · 602 阅读 · 0 评论 -
Golang中使用defer的那些坑
defer用来声明一个延迟函数,把这个函数放入到一个栈上,当外部的包含方法return之前,返回参数到调用方法之前调用,也可以说是运行到最外层方法体时调用。我们经常用他来做一些资源的释放,比如关闭io操作。defer是golang的一个特色功能,被称为“延迟调用函数”。当外部函数返回后执行defer。类似于其他语言的 try… catch … finally… 中的finally,当然差别还是明显的。在使用defer之前我们应该多了解defer的特性,这样才能避免使用上的误区。原创 2023-04-22 00:30:00 · 195 阅读 · 0 评论 -
详解Golang中的反射及反射结构体
反射是在golang程序运行时检查变量所具有类型的一种机制。由于反射可以得出关于变量结构的数据(即“关于数据的数据”),所以这也被认为是golang元编程的基础。原创 2023-04-21 08:00:00 · 1003 阅读 · 0 评论 -
Golang爬虫实战案例
随着网络的迅速发展,万维网成为大量信息的载体,如何有效地提取并利用这些信息成为一个巨大的挑战。搜索引擎(Search Engine),例如传统的通用搜索引擎AltaVista,Yahoo!和Google等,作为一个辅助人们检索信息的工具成为用户访问万维网的入口和指南。但是,这些通用性搜索引擎也存在着一定的局限性,如:(1)不同领域、不同背景的用户往往具有不同的检索目的和需求,通过搜索引擎所返回的结果包含大量用户不关心的网页。原创 2023-04-20 22:21:06 · 825 阅读 · 0 评论 -
Go 语言读取文件的几种方式
本文介绍了 Go 语言读取文件的几种方式,函数将整个文件读成一个字符串。这个函数很方便,但不应该用于非常大的文件。希望能对你有所帮助!原创 2023-04-19 00:00:00 · 1666 阅读 · 0 评论 -
Golang中的原子操作详解
原子操作是变量级别的互斥锁。原子操作是变量级别的互斥锁。简单来说,就是同一时刻,只能有一个 CPU 对变量进行读或写。当我们想要对某个变量做并发安全的修改,除了使用官方提供的Mutex,还可以使用包的原子操作, 它能够保证对变量的读取或修改期间不被其他的协程所影响。我们可以用下图来表示:说明:在上图中,我们有三个 CPU 逻辑核,其中 CPU 1 正在对变量v做原子操作,这个时候 CPU 2 和 CPU 3 不能对v做任何操作, 在 CPU 1 操作完成后,CPU 2 和 CPU 3 可以获取到v。原创 2023-03-27 19:58:36 · 1846 阅读 · 0 评论 -
Golang中new 和make 关键字的区别
本篇文章来介绍一道非常常见的面试题,到底有多常见呢?可能很多面试的开场白就是由此开始的。那就是 new 和 make 这两个内置函数的区别。其实这个问题本身并不复杂,简单来说就是,new 只分配内存,而 make 只能用于 slice、map 和 chan 的初始化,下面我们就来详细介绍一下。原创 2023-03-27 19:42:40 · 141 阅读 · 0 评论 -
Golang进阶 —— API接口的设计
在之前的几篇文章中,我们从如何实现最简单的HTTP服务器,到如何对路由进行改进,到如何增加中间件。总的来讲,我们已经把Web服务器相关的内容大概梳理了一遍了。在这一篇文章中,我们将从最简单的一个main函数开始,慢慢重构,来研究如何把API设计的更加规范和具有扩展性。在这这篇文章中,我先不使用MySQL和Redis,缓存和持久化相关的内容我将在以后的文章中提到。在这个系列中,我们主要还是聊聊与Web有关的内容。原创 2023-04-02 01:00:00 · 1035 阅读 · 0 评论 -
Golang进阶 —— 中间件的设计
在上一篇文章中,我们已经可以实现一个性能较高,且支持RESTful风格的路由了。但是,在Web应用的开发中,我们还需要一些可以被扩展的功能。因此,在设计框架的过程中,应该留出可以扩展的空间,比如:日志记录、故障恢复等功能,如果我们把这些业务逻辑全都塞进Controller/Handler中,会显得代码特别的冗余,杂乱。所以在这篇文章中,我们来探究如何更优雅的设计这些中间件。原创 2023-04-02 00:45:00 · 621 阅读 · 0 评论 -
Golang进阶 —— 实现一个RESTful风格的路由
在上一篇文章中,我们聊了聊在Golang中怎么实现一个Http服务器。但是在最后我们可以发现,固然DefaultServeMux可以做路由分发的功能,但是他的功能同样是不完善的。由DefaultServeMux做路由分发,是不能实现RESTful风格的API的,我们没有办法定义请求所需的方法,也没有办法在API路径中加入query参数。其次,我们也希望可以让路由查找的效率更高。所以在这篇文章中,我们将分析httprouter这个包,从源码的层面研究他是如何实现我们上面提到的那些功能。并且,对于这原创 2023-04-02 00:15:00 · 397 阅读 · 0 评论 -
Golang进阶 —— Http服务器详解
由于Golang优秀的并发处理,很多公司使用Golang编写微服务。对于Golang来说,只需要短短几行代码就可以实现一个简单的Http服务器。加上Golang的协程,这个服务器可以拥有极高的性能。然而,正是因为代码过于简单,我们才应该去研究他的底层实现,做到会用,也知道为什么这么用。在本文中,会以自顶向下的方式,从如何使用,到如何实现,一点点的分析Golang中net/http这个包中关于Http服务器的实现方式。内容可能会越来越难理解,作者会尽量把这些源码讲的更清楚一些,希望对各位有所帮助。原创 2023-04-01 00:00:00 · 1913 阅读 · 0 评论 -
Socket封装数据详解(Golang版)
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。我们知道两个进程如果需要进行通讯最基本的一个前提能能够唯一的标示一个进程,在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,这时候我们需要另辟它径了,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程,能够唯一标示网络中的进程后,它们就可以利用sock原创 2023-03-27 18:20:55 · 730 阅读 · 0 评论 -
Go并发编程详解
随着硬件的发展,并发程序变得越来越重要。Web服务器会一次处理成千上万的请求。平板电脑和手机app在渲染用户画面同时还会后台执行各种计算任务和网络请求。即使是传统的批处理问题--读取数据,计算,写输出--现在也会用并发来隐藏掉I/O的操作延迟以充分利用现代计算机设备的多个核心。计算机的性能每年都在以非线性的速度增长。原创 2022-12-04 20:16:09 · 1298 阅读 · 0 评论 -
GO语言的文件操作
字符串在开发中使用频率较高,我们经常需要对字符串进行拆分、判断等操作,可以借助Go标准库中的strings包快速达到处理字符串的目录。Open()是以只读权限打开文件名为name的文件,得到的文件指针file,只能用来对文件进行“读”操作。因此,有时需要指定到某一个目录下,根据目录存储的状况再进行文件的特定操作。打开目录我们也使用 OpenFile 函数,但要指定不同的参数来通知系统,要打开的是一个目录文件。如:我们可以提示用户提供一个目录位置,打开该目录,查看目录下的所有成员,并判别他们是文件还是目录。原创 2022-11-18 03:08:25 · 380 阅读 · 0 评论 -
GO语言中的结构体详解
如果结构体的全部成员都是可以比较的,那么结构体也是可以比较的,那样的话两个结构体将可以使用 == 或!有时我们需要将不同类型的数据组合成一个有机的整体,如:一个学生有学号/姓名/性别/年龄/地址等属性。传参过程中,实参会将自己的值拷贝一份给形参。近乎100%的使用都采用“传址”的方式,将结构体的。结构体是一种聚合的数据类型,它是由一系列具有相同类型或不同类型的数据构成的数据集合。每个数据称为结构体的成员。在Go语言中,普通结构体变量 和 结构体指针变量发访问成员的方法一致。原创 2022-11-18 02:44:58 · 983 阅读 · 0 评论 -
GO语言中的Map使用详解
Go语言中的map(映射、字典)是一种内置的数据结构,它是一个无序的key-value对的集合,比如以身份证号作为唯一键来标识一个人的信息。Go语言中并没有提供一个set类型,但是map中的key也是不相同的,可以用map实现类似set的功能。原创 2022-11-18 02:32:01 · 12692 阅读 · 0 评论 -
GO语言中指针的使用
指针是一个代表着某个内存地址的值。这个内存地址往往是在内存中存储的另一个变量的值的起始位置。Go语言对指针的支持介于Java语言和C/C++语言之间,它既没有想Java语言那样取消了代码对指针的直接操作的能力,也避免了C/C++语言中由于对指针的滥用而造成的安全和可靠性问题。原创 2022-11-18 02:17:04 · 614 阅读 · 0 评论 -
GO语言中切片的使用及详细说明
数组的长度在定义之后无法再次修改;数组是值类型,每次传递都将产生一份副本。显然这种数据结构无法完全满足开发者的真实需求。Go语言提供了数组切片(slice)来弥补数组的不足。原创 2022-11-18 00:42:10 · 657 阅读 · 0 评论 -
Go语言中数组的定义及基本使用
数组的定义:一、使用传统方式定义数组: 定义:var 数组名 [元素个数]数据类型 如:var arr [8]int=[8]int二、使用自动类型推导创建数组 定义:数组名:=[元素个数]数据类型 如:arr:=[10]int三、使用三个点的自动类型推导,可以根据元素个数创建数组,数组长度可以随...原创 2020-02-01 04:54:07 · 4131 阅读 · 0 评论