Какво прави go vet ./...
?
Какво е Oracle
? В контекста на golang.
Как може да видим errno
на C функция, която сме извикали?
nil
ако errno
е бил вдигнат
Какво прави select
?
select { case result := <-google: fmt.Printf("received %v from google\n", result) case result := <-bing: fmt.Printf("received %v from bing\n", result) case <- time.After(1 * time.Second): fmt.Printf("timed out\n") }
-x го кара да принтира какво всъщност прави:
-> go build -x github.com/Vladimiroff/vec2d WORK=/tmp/go-build495023012 mkdir -p $WORK/github.com/Vladimiroff/vec2d/_obj/ mkdir -p $WORK/github.com/Vladimiroff/ cd /home/mstoykov/workspace/go/src/github.com/Vladimiroff/vec2d /home/mstoykov/workspace/goroot/go/pkg/tool/linux_amd64/compile -o $WORK/github.com/Vladimiroff/vec2d.a -trimpath $WORK -p github.com/Vladimiroff/vec2d -complete -buildid 577672012d89431ef32536b66f5254f5f6f49189 -D _/home/mstoykov/workspace/go/src/github.com/Vladimiroff/vec2d -I $WORK -pack ./utils.go ./vector.go
var gopher int32 = 2014
type Location struct { // float64 -> 8 bytes X, Y, Z float64 // 24 bytes in total } var Locations [1000]Location // 24 * 1000 bytes stored *sequnetially*
=> По-добро използване на кеша
Бе върши се доста работа по темата.
package util func Max(a, b int) int { if a > b { return a } return b }
---
package main func double(a, b int) int { return 2 * util.Max(a, b) }
package main func double(a, b int) int { max := b if a > b { max = a } return 2 * max }
func LargeAndComplicatedAction() { if false { [...] } [...] }
func DebugChecks() bool { return debugBuildTagIsOn } func LargeAndComplicatedAction() { if DebugChecks() { [...] } [...] }
Кое къде отива в С, примерно?
malloc
отива на хийпаТолкова е просто. Хайде сега на Go
func SumFirst100() int { numbers := make([]int, 100) for i := range numbers { numbers[i] = i + 1 } var sum int for _, i := range numbers { sum += i } return sum }
numbers
?type Cursor struct { X, Y int } const width, height = 640, 480 func Center(c *Cursor) { c.X += width / 2 c.Y += height / 2 } func CenterCursor() (int, int) { c := new(Cursor) Center(c) return c.X, c.Y }
new(Cursor)
?-> go build -gcflags=-m esc.go # command-line-arguments ./esc.go:9: can inline Center ./esc.go:14: can inline CenterCursor ./esc.go:16: inlining call to Center ./esc.go:9: Center c does not escape ./esc.go:15: CenterCursor new(Cursor) does not escape ./esc.go:22: SumFirst100 make([]int, 100) does not escape
Cooperatively scheduled
Сценарий: Изпълняваме thread на C.
int ack(int m, int n) { if (m == 0) { return n + 1; } else if (m > 0 && n == 0) { return ack(m - 1, 1); } else { return ack(m - 1, ack(m, n - 1)); } } ack(4, 5); // segmentation fault
Рекурсия. Свърши ни паметта на стека.
Да, това ще понася по-дълбока рекурсия, но пък ще заделяме повече памет за
АБСОЛЮТНО всяка функция, която тя може да не използва.
Ще знаем точно колко голям стек да заделяме за всяка функция, но този анализ ще
отнема време, което води до бавна компилация с много налучкване или бавно
изпълнение на всяка функция
Това е начинът, по който Go до версия 1.3 управляваше стековете.
morestack
morestack
заделя нова памет за стек+---------------+ | | | unused | | stack | | space | +---------------+ | Foobar | | | +---------------+ +---------------+ | | +-->| Foobar | | lessstack | | | | +---------------+ | +---------------+ | Stack info |---+ | rest of stack | | | | | +---------------+ +---------------+
Но има и проблеми
Отдолу имплементацията на кратко (и значително опрoстено):
- цикличен буфер за стойностите на канала
- една опашка с писари
- една опашка с четци
- един lock
- един bool дали е затворен
- малко допълнителни неща за по-бързо (грозна) имплементация
Били са открити някои неща, които се случват МНОГО често. Те са били оптимизирани.
Поради нужди на имплементацията на Go има едно известно количесто ... 'яки' коментари.
Те са такива защото правят неща които няма как да се направят с другите части на езика и същевремнно лъхат на развалено кисело зеле.