• [放鞭炮][福]玉竹斑斑节日快乐![福][放鞭炮] 2019-05-23
  • 三狮军团首秀 只有两千多球迷观战 2019-05-19
  • 人民网2017呼和浩特徒步迎新活动--内蒙古频道--人民网 2019-05-19
  • 【品牌资讯】环球网斩获“全国行业新闻网站传播力2017年6月榜”多项冠军 2019-05-15
  • 深化对经济工作主线的认识 从供需关系看供给侧结构性改革 2019-05-15
  • 格拉斯哥艺术学院起火 4年前曾遭火灾仍在整修 2019-05-14
  • 回复@地瓜干17世:猪临死才会嚎叫呢~ 2019-05-14
  • 婺源古村溪中发现鹰嘴龟 2019-05-08
  • 编辑评测:高夫净源控油平衡露 极速补水长效控油 2019-05-08
  • 四部门发文规范特色小镇建设防止“新瓶装旧酒” 2019-05-02
  • 【地球的盛会文明的聚会艺术的盛宴四海一家足球为人类和平幸福而荣耀!!!普京是当今人类世界最优秀的一代伟人俄罗斯赢啦!!!】 2019-04-29
  • 学习新思想,千万师生同上一堂课 2019-04-28
  • 你这种个体户都干不了的老蚕也配谈计划?真是笑死人不偿命哦? 2019-04-23
  • 感人!的哥带着患病父亲出车 孝心感动乘客 2019-04-23
  • 图解:习近平在纪念马克思诞辰200周年大会上讲话的16个金句 2019-04-16
  • 今天山西快乐十分开奖:golang高并发的深入理解

    山西体彩11选5直选遗漏 www.caxru.com  更新时间:2019年03月10日 15:29:10   作者:飞翔码农   我要评论

    golang从语言级别上对并发提供了支持,而且在启动并发的方式上直接添加了语言级的关键字。下面这篇文章主要给大家介绍了关于golang高并发的相关资料,需要的朋友可以参考下

    前言

    GO语言在WEB开发领域中的使用越来越广泛,Hired 发布的《2019 软件工程师状态》报告中指出,具有 Go 经验的候选人是迄今为止最具吸引力的。平均每位求职者会收到9 份面试邀请。


    想学习go,最基础的就要理解go是怎么做到高并发的。

    那么什么是高并发?

    高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计保证系统能够同时并行处理很多请求。

    严格意义上说,单核的CPU是没法做到并行的,只有多核的CPU才能做到严格意义上的并行,因为一个CPU同时只能做一件事。那为什么是单核的CPU也能做到高并发。这就是操作系统进程线程调度切换执行,感觉上是并行处理了。所以只要进程线程足够多,就能处理C1K C10K的请求,但是进程线程的数量又受到操作系统内存等资源的限制。每个线程必须分配8M大小的栈内存,不管是否使用。每个php-fpm需要占用大约20M的内存。所以目前有线程的Java就比只有进程的PHP的并发处理能力高。当然了,软件的处理能力不仅仅跟内存有关,还有是否阻塞,是否异步处理,CPU等等。Nginx作为单线程的模型却可以承担几万甚至几十万的并发请求,Nginx的话题说起来也就更多了。
    我们继续聊我们的Go,那么是不是可以有一种语言使用更小的处理单元,占用内存比线程更小,那么它的并发处理能力就可以更高。所以Google就做了这件事,就有了golang语言,golang从语言层面就支持了高并发。

    go为什么能做到高并发

    goroutine是Go并行设计的核心。goroutine说到底其实就是协程,但是它比线程更小,几十个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB),当然会根据相应的数据伸缩。也正因为如此,可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便。

    一些高并发的处理方案基本都是使用协程,openresty也是利用lua语言的协程做到了高并发的处理能力,PHP的高性能框架Swoole目前也在使用PHP的协程。

    协程更轻量,占用内存更小,这是它能做到高并发的前提。

    go web开发中怎么做到高并发的能力

    学习go的HTTP代码。先创建一个简单的web服务。

    package main
    
    import (
     "fmt"
     "log"
     "net/http"
    )
    
    func response(w http.ResponseWriter, r *http.Request) {
     fmt.Fprintf(w, "Hello world!") //这个写入到w的是输出到客户端的
    }
    
    func main() {
     http.HandleFunc("/", response)
     err := http.ListenAndServe(":9000", nil)
     if err != nil {
      log.Fatal("ListenAndServe: ", err)
     }
    }

    然后编译

    go build -o test_web.gobin
    ./test_web.gobin

    然后访问

    curl 127.0.0.1:9000
    Hello world!

    这样简单的一个WEB服务就搭建起来。接下来我们一步一步理解这个Web服务是怎么运行的,怎么做到高并发的。
    我们顺着http.HandleFunc("/", response)方法顺着代码一直往上看。

    func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
     DefaultServeMux.HandleFunc(pattern, handler)
    }
    var DefaultServeMux = &defaultServeMux
    var defaultServeMux ServeMux
    
    type ServeMux struct {
     mu sync.RWMutex//读写锁。并发处理需要的锁
     m  map[string]muxEntry//路由规则map。一个规则一个muxEntry
     hosts bool //规则中是否带有host信息
    }
    一个路由规则字符串,对应一个handler处理方法。
    type muxEntry struct {
     h  Handler
     pattern string
    }

    上面是DefaultServeMux的定义和说明。我们看到ServeMux结构体,里面有个读写锁,处理并发使用。muxEntry结构体,里面有handler处理方法和路由字符串。

    接下来我们看下,http.HandleFunc函数,也就是DefaultServeMux.HandleFunc做了什么事。我们先看mux.Handle第二个参数HandlerFunc(handler)

    func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
     mux.Handle(pattern, HandlerFunc(handler))
    }
    type Handler interface {
     ServeHTTP(ResponseWriter, *Request) // 路由实现器
    }
    type HandlerFunc func(ResponseWriter, *Request)
    func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
     f(w, r)
    }

    我们看到,我们传递的自定义的response方法被强制转化成了HandlerFunc类型,所以我们传递的response方法就默认实现了ServeHTTP方法的。

    我们接着看mux.Handle第一个参数。

    func (mux *ServeMux) Handle(pattern string, handler Handler) {
     mux.mu.Lock()
     defer mux.mu.Unlock()
    
     if pattern == "" {
      panic("http: invalid pattern")
     }
     if handler == nil {
      panic("http: nil handler")
     }
     if _, exist := mux.m[pattern]; exist {
      panic("http: multiple registrations for " + pattern)
     }
    
     if mux.m == nil {
      mux.m = make(map[string]muxEntry)
     }
     mux.m[pattern] = muxEntry{h: handler, pattern: pattern}
    
     if pattern[0] != '/' {
      mux.hosts = true
     }
    }

    将路由字符串和处理的handler函数存储到ServeMux.m 的map表里面,map里面的muxEntry结构体,上面介绍了,一个路由对应一个handler处理方法。

    接下来我们看看,http.ListenAndServe(":9000", nil)做了什么

    func ListenAndServe(addr string, handler Handler) error {
     server := &Server{Addr: addr, Handler: handler}
     return server.ListenAndServe()
    }
    
    func (srv *Server) ListenAndServe() error {
     addr := srv.Addr
     if addr == "" {
      addr = ":http"
     }
     ln, err := net.Listen("tcp", addr)
     if err != nil {
      return err
     }
     return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
    }

    net.Listen("tcp", addr) ,就是使用端口addr用TCP协议搭建了一个服务。tcpKeepAliveListener就是监控addr这个端口。

    接下来就是关键代码,HTTP的处理过程

    func (srv *Server) Serve(l net.Listener) error {
     defer l.Close()
     if fn := testHookServerServe; fn != nil {
      fn(srv, l)
     }
     var tempDelay time.Duration // how long to sleep on accept failure
    
     if err := srv.setupHTTP2_Serve(); err != nil {
      return err
     }
    
     srv.trackListener(l, true)
     defer srv.trackListener(l, false)
    
     baseCtx := context.Background() // base is always background, per Issue 16220
     ctx := context.WithValue(baseCtx, ServerContextKey, srv)
     for {
      rw, e := l.Accept()
      if e != nil {
       select {
       case <-srv.getDoneChan():
        return ErrServerClosed
       default:
       }
       if ne, ok := e.(net.Error); ok && ne.Temporary() {
        if tempDelay == 0 {
         tempDelay = 5 * time.Millisecond
        } else {
         tempDelay *= 2
        }
        if max := 1 * time.Second; tempDelay > max {
         tempDelay = max
        }
        srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
        time.Sleep(tempDelay)
        continue
       }
       return e
      }
      tempDelay = 0
      c := srv.newConn(rw)
      c.setState(c.rwc, StateNew) // before Serve can return
      go c.serve(ctx)
     }
    }

    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)做的??聪麓?/p>

    func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
     handler := sh.srv.Handler
     if handler == nil {
      handler = DefaultServeMux
     }
     if req.RequestURI == "*" && req.Method == "OPTIONS" {
      handler = globalOptionsHandler{}
     }
     handler.ServeHTTP(rw, req)
    }

    handler为空,就我们刚开始项目中的ListenAndServe第二个参数。我们是nil,所以就走DefaultServeMux,我们知道开始路由我们就设置的是DefaultServeMux,所以在DefaultServeMux里面我一定可以找到请求的路由对应的handler,然后执行ServeHTTP。前边已经介绍过,我们的reponse方法为什么具有ServeHTTP的功能。流程大概就是这样的。

    我们看下流程图


    结语

    我们基本已经学习忘了GO 的HTTP的整个工作原理,了解到了它为什么在WEB开发中可以做到高并发,这些也只是GO的冰山一角,还有Redis MySQL的连接池。要熟悉这门语言还是多写多看,才能掌握好它。灵活熟练的使用。

    好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

    相关文章

    • go语言通过zlib压缩数据的方法

      go语言通过zlib压缩数据的方法

      这篇文章主要介绍了go语言通过zlib压缩数据的方法,实例分析了Go语言中zlib的使用技巧,需要的朋友可以参考下
      2015-03-03
    • GO语言基本类型分析

      GO语言基本类型分析

      这篇文章主要介绍了GO语言基本类型,较为详细的分析了整形、浮点型、字符串、指针等类型的具体用法,是深入学习GO语言所必须掌握的重要基础,需要的朋友可以参考下
      2014-12-12
    • Go语言实现的web爬虫实例

      Go语言实现的web爬虫实例

      这篇文章主要介绍了Go语言实现的web爬虫,实例分析了web爬虫的原理与Go语言的实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
      2015-02-02
    • Go语言服务器开发实现最简单HTTP的GET与POST接口

      Go语言服务器开发实现最简单HTTP的GET与POST接口

      这篇文章主要介绍了Go语言服务器开发实现最简单HTTP的GET与POST接口,实例分析了Go语言http包的使用技巧,需要的朋友可以参考下
      2015-02-02
    • golang复用http.request.body的方法示例

      golang复用http.request.body的方法示例

      这篇文章主要给大家介绍了关于golang复用http.request.body的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
      2018-10-10
    • golang实现简易的分布式系统方法

      golang实现简易的分布式系统方法

      这篇文章主要介绍了golang实现简易的分布式系统方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
      2018-10-10
    • Go语言的os包中常用函数初步归纳

      Go语言的os包中常用函数初步归纳

      这篇文章主要介绍了Go语言的os包中常用函数初步归纳,用于一些和系统交互功能的实现,需要的朋友可以参考下
      2015-10-10
    • Go语言里的new函数用法分析

      Go语言里的new函数用法分析

      这篇文章主要介绍了Go语言里的new函数用法,实例分析了new函数的功能及使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
      2015-02-02
    • GO语言并发编程之互斥锁、读写锁详解

      GO语言并发编程之互斥锁、读写锁详解

      这篇文章主要介绍了GO语言并发编程之互斥锁、读写锁详解,本文是GO并发编程实战一书的样章,详细讲解了互斥锁、读写锁,然后给出了一个完整示例,需要的朋友可以参考下
      2014-11-11
    • Golang学习笔记(一):简介

      Golang学习笔记(一):简介

      这篇文章主要介绍了Golang学习笔记(一):简介,本文讲解了Go语言最主要的特性、安装、环境变量设置、整体目录结构、Helloworld、go命令、调试、编辑器设置等内容,需要的朋友可以参考下
      2015-05-05

    最新评论

  • [放鞭炮][福]玉竹斑斑节日快乐![福][放鞭炮] 2019-05-23
  • 三狮军团首秀 只有两千多球迷观战 2019-05-19
  • 人民网2017呼和浩特徒步迎新活动--内蒙古频道--人民网 2019-05-19
  • 【品牌资讯】环球网斩获“全国行业新闻网站传播力2017年6月榜”多项冠军 2019-05-15
  • 深化对经济工作主线的认识 从供需关系看供给侧结构性改革 2019-05-15
  • 格拉斯哥艺术学院起火 4年前曾遭火灾仍在整修 2019-05-14
  • 回复@地瓜干17世:猪临死才会嚎叫呢~ 2019-05-14
  • 婺源古村溪中发现鹰嘴龟 2019-05-08
  • 编辑评测:高夫净源控油平衡露 极速补水长效控油 2019-05-08
  • 四部门发文规范特色小镇建设防止“新瓶装旧酒” 2019-05-02
  • 【地球的盛会文明的聚会艺术的盛宴四海一家足球为人类和平幸福而荣耀!!!普京是当今人类世界最优秀的一代伟人俄罗斯赢啦!!!】 2019-04-29
  • 学习新思想,千万师生同上一堂课 2019-04-28
  • 你这种个体户都干不了的老蚕也配谈计划?真是笑死人不偿命哦? 2019-04-23
  • 感人!的哥带着患病父亲出车 孝心感动乘客 2019-04-23
  • 图解:习近平在纪念马克思诞辰200周年大会上讲话的16个金句 2019-04-16
  • 北京赛车pk10官网 竟彩首页比分直播 北京快乐8开奖视频 安徽快3 幸运赛车视频直播 北京赛车走势图 排列五开奖号码走势图 下载重庆时时彩 天津时时彩官方网址 北京pk10一期一码网站 即开型福彩中奖率低 2019欢乐生肖1025开奖 新时时彩倍投计算 微信北京赛车赌博 北京胜平负比分直播 体彩p3奖号947前后关系