zoukankan      html  css  js  c++  java
  • Go http server 高并发

    先来个段子:【并发处理连接数】

    多高?

    很高!

    到底多高?

    没有一亿,都算少了!

    .

    .

    .

    然后就没有然后了。。。

    “段子 END”

    这就是目前中国企业的通病:提个概念,没有答案,最后造成概念也模糊了,其实,我感觉它根本不知道要干什么!从头到脚都是病啊!

    下面,我们谈谈,web服务连接和速度问题

    现在,随着网络普及,对于服务的响应速度和并发处理能力都有了不同寻常的要求

    所以,对于服务的标准也越来越高

    我以最简洁的说法把问题描述一下,其它不解释

    1. 响应速度,是指:对于客户端请求的事务处理时间的快慢,一般,要用分布式处理来快速得到可以分布式处理的事务的结果

    2. 并发处理,是指:对于客户端的请求的事务可以并行在服务端处理,一盘要有线程池,工作者的逻辑概念介入

    需要澄清一个概念,并发不是指客户端并发连接到服务器!!!!!!,这个是大多数中国开发者的死穴,而且死不悔改!!!!!

    所以,你要好好考虑一下,这些固执的人群里,算不算有你有一个!!!

    3. 服务器硬件性能越高,自然并发能力越高(多CPU,多内核);分布式算法优秀,自然响应越快了

    好吧,关于文字,我就算这么多,我的博文不是教小白上路的,而是给学者指出路上哪里有坑的。希望你好好揣摩,也许直到今天你也是不懂web的吧

    //DEMO

    下面,还是上例程,出自于国外的一篇文章。

    原作者,出于公司商业性质,说了90%的话,剩下的10%有问题,这些都体现在他给出的源码里露出了马脚,当然这就是把正确改不能用的代价。原谅他吧,搁你身上也一样。这就是公司,万恶的公司,不关作者的事,他只是想得意一下而已!

    如果你看了他的文章和源码,你还是跑不起来的,所以,听我的,看我的吧

    还是那句话,不过多解释,但不会不说明,如果你需要掰着指头教你写1,2,3,那么请回到亲爱的小学,去找老去的园丁吧,哈哈哈(对了,推荐电影:神秘代码)

    /////////////////////////////////////

    //go-server-effic.go

    package main

    import (
      "fmt"
      "os"
      "runtime"
      "net/http"
    )

    var (
      //Max_Num = os.Getenv("MAX_NUM")
      MaxWorker = runtime.NumCPU()
      MaxQueue = 1000
    )

    type Serload struct {
      pri string
    }

    type Job struct {
      serload Serload
    }

    var JobQueue chan Job

    type Worker struct {
      WorkerPool chan chan Job
      JobChannel chan Job
      Quit chan bool
    }

    func NewWorker(workPool chan chan Job) Worker {
      return Worker {
        WorkerPool:workPool,
        JobChannel:make(chan Job),
        Quit:make(chan bool),
      }
    }

    func (w Worker) Start() {
      go func() {
        for {
          w.WorkerPool <- w.JobChannel
          select {
          case job:= <- w.JobChannel:
            // excute job
            fmt.Println(job.serload.pri)
          case <- w.Quit:
            return
          }
        }
      }()
    }

    func (w Worker) Stop() {
      go func() {
        w.Quit <- true
      }()
    }

    type Dispatcher struct {
      MaxWorkers int
      WorkerPool chan chan Job
      Quit chan bool
    }

    func NewDispatcher(maxWorkers int) *Dispatcher {
      pool := make(chan chan Job, maxWorkers)
      return &Dispatcher{MaxWorkers:maxWorkers, WorkerPool:pool, Quit:make(chan bool)}
    }

    func (d *Dispatcher) Run() {
      for i:=0; i<d.MaxWorkers; i++ {
        worker := NewWorker(d.WorkerPool)
        worker.Start()
      }

      go d.Dispatch()
    }

    func (d *Dispatcher) Stop() {
      go func() {
        d.Quit <- true
      }()
    }

    func (d *Dispatcher) Dispatch() {
      for {
        select {
        case job:=<- JobQueue:
          go func(job Job) {
            jobChannel := <- d.WorkerPool
            jobChannel <- job
          }(job)
        case <- d.Quit:
          return
        }
      }
    }

    func entry(res http.ResponseWriter, req *http.Request) {
      // fetch job
      work := Job{serload:Serload{pri:"Just do it"}}
      JobQueue <- work
      fmt.Fprintf(res, "Hello World ...again")
    }

    func init() {
      runtime.GOMAXPROCS(MaxWorker)
      JobQueue = make(chan Job, MaxQueue)
      dispatcher := NewDispatcher(MaxWorker)
      dispatcher.Run()
    }

    func main() {
      Port := "8086"
      IsHttp := true
      arg_num := len(os.Args)
      if 2<=arg_num {
        Port = os.Args[1]
      }
      if 3<=arg_num {
        if os.Args[2]=="true" {
          IsHttp = true
        } else {
          IsHttp = false
        }
      }
      fmt.Printf("server is http %t ", IsHttp)
      fmt.Println("server listens at ", Port)

      http.HandleFunc("/", entry)

      var err error
      if IsHttp {
        err = http.ListenAndServe(":"+Port, nil)
      } else {
        err = http.ListenAndServeTLS(":"+Port, "server.crt", "server.key", nil)
      }
      if err != nil {
        fmt.Println("Server failure /// ", err)
      }

      fmt.Println("quit")
    }

    //结果

    Finally:

    为了避免大家陷入困境,我只给大家指出思路,这样就不会引导大家进入似懂非懂的怪圈

    1. 协程池里的协程数目应该与CPU内核数一致,这个好理解,这时候效率和利用率都是最高的

    2. 每个协程运行一个工作者出来处理客户端请求(我们就是简单的打印出“Just do it”而已,不在于复杂度,在于处理流程)

    好吧,再简单讲讲代码

    首先,请自己去学习:Go的协程和渠道(文字概念可以去看书,例子,我之前的博文都有涉及,保证都是可运行的例子)

    这个demo的核心:

    1. 工作者工作协程,挂入调度器,取Job,执行Job,周而复始

    2. 调度器,从Job队列取Job,分配给工作者,周而复始

    3. web响应里,模拟了客户的请求-Job,并将此Job放入Job队列,只有有客户端请求,就周而复始的工作

    好了,真的好了

    师傅领进门,修行在个人

    哈哈,我是教"孙悟空"的导师!,哈哈哈哈哈

    祝你Go的快,Go的好,Go的高

    关于Go,大概真的只能到这里啦,天下没有不散的宴席,就到这儿吧

    祝,顺利!!!!!

  • 相关阅读:
    Sublime text追踪函数插件:ctags
    上传项目后服务器的一些设置
    svg可缩放矢量图形
    定时备份mysql
    phpstudy配置ssl
    thinkphp数据表操作恐怖事件。
    把一个数组和另一个数组放进同一个数组
    mysql数据库备份与还原命令
    mysql一些有用的链接
    MySQL各版本的区别
  • 原文地址:https://www.cnblogs.com/woodzcl/p/7602530.html
Copyright © 2011-2022 走看看