golang 为什么能做到高并发
goroutine是go并行的关键,goroutine说到底就是携程,但是他比线程更小,几十个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB),当然会根据相应的数据伸缩。也正因为如此,可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便。
一些高并发的处理方案基本都是使用协程,openresty也是利用lua语言的协程做到了高并发的处理能力,PHP的高性能框架Swoole目前也在使用PHP的协程。
协程更轻量,占用内存更小,这是它能做到高并发的前提。
go web开发中怎么做到高并发的能力
学习go的HTTP代码。先创建一个简单的web服务。
然后启动
这样简单的一个WEB服务就搭建起来。接下来我们一步一步理解这个Web服务是怎么运行的,怎么做到高并发的。
我们顺着http.HandleFunc("/", response)方法顺着代码一直往上看。
上面是DefaultServeMux的定义和说明。我们看到ServeMux结构体,里面有个读写锁,处理并发使用。muxEntry结构体,里面有handler处理方法和路由字符串。
接下来我们看下,http.HandleFunc函数,也就是DefaultServeMux.HandleFunc做了什么事。我们先看mux.Handle第二个参数HandlerFunc(handler)
我们看到,我们传递的自定义的response方法被强制转化成了HandlerFunc类型,所以我们传递的response方法就默认实现了ServeHTTP方法的。
我们接着看mux.Handle第一个参数。
将路由字符串和处理的handler函数存储到ServeMux.m 的map表里面,map里面的muxEntry结构体,上面介绍了,一个路由对应一个handler处理方法。
接下来我们看看,http.ListenAndServe(":9000", nil)做了什么
net.Listen("tcp", addr),就是使用端口addr用TCP协议搭建了一个服务。tcpKeepAliveListener就是监控addr这个端口。
接下来就是关键代码,HTTP的处理过程
for里面l.Accept()接受TCP的连接请求,c := srv.newConn(rw)创建一个Conn,Conn里面保存了该次请求的信息(srv,rw)。启动goroutine,把请求的参数传递给c.serve,让goroutine去执行。
这个就是GO高并发最关键的点。每一个请求都是一个单独的goroutine去执行。
那么前面设置的路由是在哪里匹配的?是在c.serverde的c.readRequest(ctx)里面分析出URI METHOD等,执行serverHandler{c.server}.ServeHTTP(w, w.req)做的。看下代码
handler为空,就我们刚开始项目中的ListenAndServe第二个参数。我们是nil,所以就走DefaultServeMux,我们知道开始路由我们就设置的是DefaultServeMux,所以在DefaultServeMux里面我一定可以找到请求的路由对应的handler,然后执行ServeHTTP。前边已经介绍过,我们的reponse方法为什么具有ServeHTTP的功能。流程大概就是这样的。
我们看下流程图
结语
我们基本已经学习忘了GO 的HTTP的整个工作原理,了解到了它为什么在WEB开发中可以做到高并发,这些也只是GO的冰山一角,还有Redis MySQL的连接池。要熟悉这门语言还是多写多看,才能掌握好它。灵活熟练的使用。