25
Go をカンストさせる話 Maxing out Go

Goをカンストさせる話

Embed Size (px)

Citation preview

Goをカンストさせる話

Maxing out Go

こんにちは

select してますか ?

select

go func(x *Daemon) {defer func() {

x.WaitGroup.Done()log.Printf("Daemon %s stopped", x.Name)

}()loop:

for {select {case cmd := <-x.CmdChan:

log.Printf("Daemon %s received command\n")go doCommand(

x,withDeadline(

x.Ctx,time.Now().Add(4*time.Second),

),cmd.Cmd,cmd.Arg,

)case <-x.Ctx.Done():

break loop}

}}(x)

selectの実装はどうなっているのか ?

case x=<-❶ case x->❷ case x=<-❸ case x=<-❹goroutine1

case x=<-❶ case x->❷goroutine2

goroutine 1

goroutine 2

goroutine 1goroutine 1

goroutine 2

goroutine 1

chan ❶ chan ❷ chan ❸ chan ❹

1. chanの waitキューに入れる2. 起こされるまで待つ3. どれに起こされたか調べる4. 該当する caseの処理に飛ぶ

大事なことはsrc/runtime/select.goに

全部書いてある

src/runtime/runtime.go

// Select statement header.// Known to compiler.// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.type hselect struct { tcase uint16 // total count of scase[] ncase uint16 // currently filled scase[] pollorder *uint16 // case poll order lockorder *uint16 // channel lock order scase [1]scase // one per case (in order of appearance)}

// Select case descriptor.// Known to compiler.// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.type scase struct { elem unsafe.Pointer // data element c *hchan // chan pc uintptr // return pc (for race detector / msan) kind uint16

tcase uint16 // total count of scase[]

uint16

65535

敵を 65535体倒すとデスペナルティの威力が最大に

所持ギルの上限は 65535ギルはぐれメタルを 1回の戦闘で複数体倒しても合計値が 65535でカウンタース

シンクロ率を 65535%にしたらダメージがオーバーフローした

65535ターン経過させると全滅扱い

HUMAN BEINGSCANNOT

HELPMAXING

ITOUT

実験

package main

import "fmt"

func main() { c := [65536]chan int{} f := fmt.Println select { case i := <-c[0]: f(i) case i := <-c[1]: f(i) case i := <-c[2]: f(i) case i := <-c[3]: f(i) case i := <-c[4]: f(i) case i := <-c[5]: f(i) case i := <-c[6]:

実験

package main

import "fmt"

func main() { c := [65536]chan int{} f := fmt.Println select { case i := <-c[0]: f(i) case i := <-c[1]: f(i) case i := <-c[2]: f(i) case i := <-c[3]: f(i) case i := <-c[4]: f(i) case i := <-c[5]: f(i) case i := <-c[6]: f(i) case i := <-c[7]: f(i)

実験

package main

import "fmt"

func main() { c := [65536]chan int{} f := fmt.Println select { case i := <-c[0]: f(i) case i := <-c[1]: f(i) case i := <-c[2]: f(i) case i := <-c[3]: f(i) case i := <-c[4]: f(i) case i := <-c[5]: f(i) case i := <-c[6]: f(i) case i := <-c[7]: f(i) case i := <-c[8]: f(i) case i := <-c[9]: f(i) case i := <-c[10]: f(i) case i := <-c[11]: f(i) case i := <-c[12]: f(i) case i := <-c[13]: f(i) case i := <-c[14]: f(i) case i := <-c[15]: f(i) case i := <-c[16]: f(i) case i := <-c[17]: f(i) case i := <-c[18]: f(i) case i := <-c[19]: f(i) case i := <-c[20]: f(i)

実験

package main

import "fmt"

func main() {c := [65536]chan int{}f := fmt.Printlnselect {case i := <-c[0]:

f(i)case i := <-c[1]:

f(i)case i := <-c[2]:

f(i)case i := <-c[3]:

f(i)case i := <-c[4]:

f(i)case i := <-c[5]:

f(i)case i := <-c[6]:

f(i)case i := <-c[7]:

f(i)case i := <-c[8]:

f(i)case i := <-c[9]:

f(i)case i := <-c[10]:

f(i)case i := <-c[11]:

f(i)case i := <-c[12]:

f(i)case i := <-c[13]:

f(i)case i := <-c[14]:

f(i)case i := <-c[15]:

f(i)case i := <-c[16]:

f(i)case i := <-c[17]:

f(i)case i := <-c[18]:

f(i)case i := <-c[19]:

f(i)case i := <-c[20]:

f(i)case i := <-c[21]:

f(i)case i := <-c[22]:

f(i)case i := <-c[23]:

f(i)case i := <-c[24]:

f(i)case i := <-c[25]:

f(i)case i := <-c[26]:

f(i)case i := <-c[27]:

f(i)case i := <-c[28]:

f(i)case i := <-c[29]:

f(i)case i := <-c[30]:

f(i)case i := <-c[31]:

f(i)case i := <-c[32]:

f(i)case i := <-c[33]:

f(i)case i := <-c[34]:

f(i)case i := <-c[35]:

f(i)case i := <-c[36]:

f(i)case i := <-c[37]:

f(i)case i := <-c[38]:

f(i)case i := <-c[39]:

f(i)case i := <-c[40]:

f(i)case i := <-c[41]:

f(i)case i := <-c[42]:

f(i)case i := <-c[43]:

f(i)case i := <-c[44]:

f(i)case i := <-c[45]:

f(i)case i := <-c[46]:

f(i)case i := <-c[47]:

f(i)case i := <-c[48]:

f(i)case i := <-c[49]:

f(i)case i := <-c[50]:

f(i)case i := <-c[51]:

f(i)case i := <-c[52]:

f(i)case i := <-c[53]:

f(i)case i := <-c[54]:

f(i)case i := <-c[55]:

f(i)case i := <-c[56]:

f(i)case i := <-c[57]:

f(i)case i := <-c[58]:

f(i)case i := <-c[59]:

f(i)case i := <-c[60]:

f(i)case i := <-c[61]:

f(i)case i := <-c[62]:

f(i)case i := <-c[63]:

f(i)case i := <-c[64]:

f(i)case i := <-c[65]:

f(i)case i := <-c[66]:

f(i)case i := <-c[67]:

f(i)case i := <-c[68]:

f(i)case i := <-c[69]:

f(i)case i := <-c[70]:

f(i)case i := <-c[71]:

f(i)case i := <-c[72]:

f(i)case i := <-c[73]:

f(i)case i := <-c[74]:

f(i)case i := <-c[75]:

f(i)case i := <-c[76]:

f(i)case i := <-c[77]:

f(i)case i := <-c[78]:

f(i)case i := <-c[79]:

f(i)case i := <-c[80]:

f(i)case i := <-c[81]:

f(i)case i := <-c[82]:

f(i)case i := <-c[83]:

f(i)case i := <-c[84]:

f(i)case i := <-c[85]:

f(i)case i := <-c[86]:

f(i)case i := <-c[87]:

f(i)case i := <-c[88]:

f(i)case i := <-c[89]:

f(i)case i := <-c[90]:

f(i)case i := <-c[91]:

f(i)case i := <-c[92]:

f(i)case i := <-c[93]:

f(i)case i := <-c[94]:

f(i)case i := <-c[95]:

f(i)

以下 65536まで続く

結果

コンパイルが終わらない

CPU100%

やがてメモリを食いつくして OOM Killerに殺される

OOM Killer のイメージ (オオアリクイ )

諦めるのはまだ早い

reflect.Select

reflect.Select

func main() { cases := [65536]reflect.SelectCase{} for i, _ := range cases { cases[i] = reflect.SelectCase{ Dir: reflect.SelectRecv, Chan: reflect.ValueOf(make(chan int)), } } go func() { for { i := rand.Int() % len(cases) cases[i].Chan.Send(reflect.ValueOf(i)) time.Sleep(time.Second) } }() fmt.Println("ready") for { c, v, ok := reflect.Select(cases[:]) fmt.Println(c, v, ok) }}

リフレクションで select相当の処理を書ける

実行結果

ubuntu:gotorture:% go run uint16maxselect.goreadyfatal error: selectrecv: too many cases

goroutine 1 [running]:runtime.throw(0x521ce0, 0x1a)...

too many cases

Questions?

ないですね

ご清聴ありがとうございました