А какво става, когато имаме много ядра?
#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
можете да вдигнете нов процесGo е един от тези езици.
go doAnotherThing()
package main import ( "fmt" "time" ) func main() { fmt.Println("Wait for my announcement...") Announce("Hello, from Goroutine!", time.Second * 2) time.Sleep(time.Second * 3) } func Announce(message string, delay time.Duration) { go func() { time.Sleep(delay) fmt.Println(message) }() }
От това, че имат една и съща памет, следва, че могат да достъпват едни и същи променливи
int i = 0 thread1 { i++ } thread2 { i++ } wait { thread1 } { thread2 } print i
Тук i
накрая може да бъде 1 или 2.
В Go имаме Semaphors и Message passing
Пакет, който ни дава синхронизационни примитиви от ниско ниво:
Cond
Mutex
Once
RWMutex
WaitGroup
Изчаква колекция от горутини да приключат и чак тогава продължава с изпълнението.
Така не правим простотии със time.Sleep
, както одеве.
package sync type WaitGroup struct {} func (*WaitGroup) Add() func (*WaitGroup) Done() func (*WaitGroup) 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 { // Increment the WaitGroup counter. wg.Add(1) // Launch a goroutine to fetch the URL. go func(url string) { // Decrement the counter when the goroutine completes. defer wg.Done() // Fetch the URL. content, err := http.Get(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()
е добра идея да бъде в defer
sync.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() }