先來個段子:【並發處理連接數】
多高?
很高!
到底多高?
沒有一億,都算少了!
.
.
.
然后就沒有然后了。。。
“段子 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\n", 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,大概真的只能到這里啦,天下沒有不散的宴席,就到這兒吧
祝,順利!!!!!