За какво можем да ползваме тестове
За какво не можем да ползваме тестове
Какво трябва да направим за да напишем тест за пакет foo
_test.gofoo или foo_testTest и приемат *testing.T като параметърfoo и да направим твърдения за крайния резултатt.Error(), t.Fail(), t.Fatal() ...
Какво прави t.Parallel()
t.Parallel()Как документираме go код
А какво става, когато имаме много ядра?
#include <stdio.h>
int main()
{
printf("before\n");
if (fork())
printf("father\n");
else
printf("son\n");
printf("both\n");
}fork създава ново копие на програмата, която изпълняваме#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t pid = fork();
if (pid == 0)
{
execl("/bin/sleep", "/bin/sleep", "2", (char *) 0);
}
else
{
waitpid(pid, NULL, 0);
}
printf("done!\n");
return 0;
}execl спира изпълнението на текущия процес и зарежда другwaitpid позволява на родителя да чака свършването на конкретен синDemo pipes.c
dup2 затваря подадения файлов дескриптор и дуплицира в него първия аргументclose затваря файлов дескриптовПротив:
За:
syscall можете да вдигнете нов процесЗа да се съсредоточим върху това, което се опитваме да кажем ще дадем скучен пример.
package main
import (
"fmt"
"time"
)
func main() {
boring("boring!")
}
func boring(msg string) { for i := 0; ; i++ { fmt.Println(msg, i) time.Sleep(1 * time.Second) } }
За конкурентноста тайминга е важен. Нека е малко по - непредвидим.
Ще сложим случайно време за сън.
package main
import (
"fmt"
"math/rand"
"time"
)
func main() { boring("boring!") } func boring(msg string) { for i := 0; ; i++ { fmt.Println(msg, i) time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond) } }
Скучната ни програма ще продължи да работи така до безкрайност. Като много скучна лекция, от която ви е неудобно да си тръгнете.
Скучната програма не заслужава вниманието ни, нека не я чакаме.
С go пускаме функция нормално, но пускащия няма нужда чака приключването й.
Пускаме goroutine.
package main import ( "fmt" "math/rand" "time" ) func main() { go boring("boring!") }
func boring(msg string) {
for i := 0; ; i++ {
fmt.Println(msg, i)
time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
}
}
Когато main приключи програмата спира.
package main import ( "fmt" "math/rand" "time" ) func main() { go boring("boring!") fmt.Println("Listening.") time.Sleep(2 * time.Second) fmt.Println("You are way too boring. I am leaving.") }
func boring(msg string) {
for i := 0; ; i++ {
fmt.Println(msg, i)
time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
}
}
Изпълнявахме main и скучната функция едновременно.
С края на main дойде и края на скучната функция.
www.youtube.com/watch?v=f6kdp27TYZs
От това, че имат една и съща памет, следва, че могат да достъпват едни и същи променливи
int i = 0
thread1 { i++ }
thread2 { i++ }
wait { thread1 } { thread2 }
print i
Тук i накрая може да бъде 1 или 2.
В Go имаме Semaphors и Message passing
Пакет, който ни дава синхронизационни примитиви от ниско ниво:
CondMutexOnceRWMutexWaitGroup
Изчаква колекция от горутини да приключат и чак тогава продължава с изпълнението.
Така не правим простотии със time.Sleep, както одеве.
package sync
type WaitGroup struct {}
func (*WaitGroup) Add()
func (*WaitGroup) Done()
func (*WaitGroup) Wait()package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
func main() { var wg sync.WaitGroup boring := func(msg string) { defer wg.Done() for i := 0; i < 8; i++ { fmt.Println(msg, i) time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond) } } wg.Add(1) go boring("boring!") fmt.Println("Waiting for the boring function to do its work") wg.Wait() }
Пак ли скуката?
package main
import (
"fmt"
"net/http"
"sync"
)
func main() { var wg sync.WaitGroup var urls = []string{ "http://www.golang.org/", "http://www.google.com/", "http://www.somestupidname.com/", } for _, url := range urls { wg.Add(1) // Increment the WaitGroup counter. // Launch a goroutine to fetch the URL. go func(url string) { defer wg.Done() // Decrement the counter when the goroutine completes. content, err := http.Get(url) // Fetch the URL. if err == nil { fmt.Println(url, content.Status) } else { fmt.Println(url, "has failed") } }(url) } // Wait for all HTTP fetches to complete. wg.Wait() }
package sync
type Mutex struct {}
func (*Mutex) Lock()
func (*Mutex) Unlock()private атрибут на наш типUnlock() е добра идея да бъде в defersync.LockerОбект от този тип ще изпълни точно една функция.
package main
import (
"fmt"
"sync"
)
func main() { var once sync.Once var wg sync.WaitGroup onceBody := func() { fmt.Println("Only once") } anotherBody := func() { fmt.Println("Another") } for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() once.Do(onceBody) once.Do(anotherBody) }() } wg.Wait() }
// In your source runtime.GOMAXPROCS(runtime.NumCPU())
# With environment variable $ GOMAXPROCS=4 go run main.go