2016-08-31 1 views
2

メインサーバーのゴルーチンによる着信要求の処理にこのような遅延があり、この遅延を回避するにはどうしてですか?バックグラウンドでのゴルーチンによる同時遅延

NOシンプルなコードがローディングローディング

とゴルーチン

package main 
import (
    "log" 
    "net/http" 
) 
func main() { 
    _ = NewTesterGo(100) 

    http.HandleFunc("/", root) 
    http.ListenAndServe(":8090", nil) 
} 
//--------------------------------------------------------------------------- 
// http handlers 
//--------------------------------------------------------------------------- 
func root(w http.ResponseWriter, r *http.Request) { 
    log.Printf("[root] `%v`\n", r.URL.Path) 
    w.Write([]byte("What the fuck")) 
} 

//--------------------------------------------------------------------------- 
// tester segment 
//--------------------------------------------------------------------------- 
type (
    TesterGo struct { 
     Work chan string 
    } 
) 

func NewTesterGo(count int) *TesterGo { 
    t:=&TesterGo{ 
     Work:make(chan string,100), 
    } 
    for ; count > 0 ; count -- { 
     go t.Worker() 
    } 
    return t 

} 
func (t *TesterGo) Worker() { 
    log.Printf("[testergo][worker][work] стартовал....\n") 
    for { 
     select { 
     case work := <-t.Work: 
      log.Printf("[testerGo][Worker] %v\n", work) 
     default: 
     } 
    } 
} 

検索結果を追加

╰─➤ wrk -d20s -t5 -c100 http://localhost:8090 
Running 20s test @ http://localhost:8090 
    5 threads and 100 connections 
    Thread Stats Avg  Stdev  Max +/- Stdev 
    Latency 17.07ms 46.63ms 368.77ms 91.73% 
    Req/Sec 10.99k  4.87k 24.48k 62.49% 
    1038912 requests in 20.10s, 128.80MB read 
Requests/sec: 51684.63 
Transfer/sec:  6.41MB 

を試験

package main 
import (
    "log" 
    "net/http" 
) 
func main() { 
    http.HandleFunc("/", root) 
    http.ListenAndServe(":8090", nil) 
} 
//--------------------------------------------------------------------------- 
// http handlers 
//--------------------------------------------------------------------------- 
func root(w http.ResponseWriter, r *http.Request) { 
    log.Printf("[root] `%v`\n", r.URL.Path) 
    w.Write([]byte("What the hell")) 
} 

結果を遅延させますの

╰─➤ wrk -d20s -t5 -c100 http://localhost:8090 
Running 20s test @ http://localhost:8090 
    5 threads and 100 connections 
    Thread Stats Avg  Stdev  Max +/- Stdev 
    Latency 464.71ms 305.44ms 1.90s 77.90% 
    Req/Sec 54.62  43.74 200.00  67.50% 
    3672 requests in 20.05s, 466.17KB read 
    Socket errors: connect 0, read 0, write 0, **timeout 97** 
Requests/sec: **183.11** 
Transfer/sec:  23.25KB 

答えて

4

あなたのゴルーチンは、チャンネル内の何も(そしてあなたの例では何もありません)が存在しない場合は、それらをすぐにスピンさせ、defaultを使用しています。これにより、Goのスケジューラは必要以上にコンテキストを切り替えることができ、おそらく何のためにも多くのCPUを消費するでしょう。

defaultには理由がありますか?仕事がありますまで

ないか、デフォルト、ゴルーチンがなり、単に「スリープ」:次のいずれかを試していない場合は。

for { 
     select { 
     case work := <-t.Work: 
      log.Printf("[testerGo][Worker] %v\n", work) 
     } 
    } 

これはところで作る選択を完全に冗長なので、ちょうどそれを取り除く:

for { //you can also use a range on the channel 
    work := <- t.Work 
    log.Printf("[testerGo][Worker] %v\n", work) 
} 

番目のオプション - 彼らはループで継続する前に待つようになりますタイムアウト:

for { 
     select { 
     case work := <-t.Work: 
      log.Printf("[testerGo][Worker] %v\n", work) 

     case <- time.After(100*time.Millisecond): //or whatever you prefer 

     } 
    } 
+0

正確に。理由を指摘していただきありがとうございます。ベンチマークに周りには誰、パフォーマンスが正常に戻りました。ありがとうございました。 – Spouk

+0

SELECT' 'で無defaultを一つだけ' case'が、その後、SELECT' 'の必要がない場合。価値があると指摘する。 – icza

+0

@icza、ええ右:)私は私の答えを変更します –

関連する問題