Колко памет се копира, когато подадем масив на функция?
Колко полета има една slice структура? Кои са те?
Възможно ли е map да има стойности от различен тип?
map[KeyType]ValueTypeКолко начина има да се създаде нова структура от тип Т? Кои са те?
Колко памет заема една структура?
А какво става, когато имаме много ядра?
#include <stdio.h>
int main()
{
printf("before\n");
if (fork())
printf("parent\n");
else
printf("child\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 позволява на родителя да чака свършването на конкретно детеПротив:
За:
syscall можете да вдигнете нов процесvoid *ticker(void *x_void_ptr) { while (42) { sleep(1); printf("tick\n"); } return NULL; } int main() { pthread_t ticker_thread; if(pthread_create(&ticker_thread, NULL, ticker, &x)) { fprintf(stderr, "Error creating thread\n"); return 1; } if(pthread_join(ticker_thread, NULL)) { fprintf(stderr, "Error joining thread\n"); return 2; } return 0;
def ticker(): while 42: print("Tick!") time.sleep(1) thread = threading.Thread(target=ticker) thread.daemon = True thread.start()
или
class TickerThread(threading.Thread): def run(self): while 42: print("Tick!") time.sleep(1) thread = TickerThread() thread.start() # ... thread.join()
За да се съсредоточим върху това, което се опитваме да кажем ще дадем скучен пример.
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
makech := make(chan uint64)
ch := make(chan []string, 100)
ch <- 64 read := <-ch
Операциите по изпращане и получаване се изпълняват с оператора <-
chan <- стойност изпраща по каналапроменлива = <-chan получава от каналаКанал може да бъде затворен
close(ch)
intChannel := make(chan int)
stringBufferedChannel := make(chan string, 5)
readOnlyChannel := make(<-chan int)
writeOnlyChannel := make(chan<- int)
c := make(chan chan int)
func doSomething(input <-chan string) {}func doSomethingElse() chan string {
result := make(chan string)
return result
}Никога не използвайте неинициализиран канал!
package main
func main() {
var c chan string
c <- "ping" // deadlock
}package main
import "fmt"
func main() {
var c chan string
fmt.Println(<-c) // deadlock
}c := make(chan int)
go func() {
list.Sort()
c <- 1
}()
doSomethingForAWhile()
<-cvar sem = make(chan struct{}, MaxOutstanding)
func handle(r *Request) {
<-sem
process(r)
sem <- struct{}{}
}
func init() {
for i := 0; i < MaxOutstanding; i++ {
sem <- struct{}{}
}
}
func Serve(queue chan *Request) {
for {
req := <-queue
go handle(req)
}
}func main() {
c := make(chan int)
c <- 42
val := <-c
println(val)
}package main import "fmt" func main() { ch := make(chan string) go func(output chan string) { for i := 0; i < 5; i++ { output <- fmt.Sprintf("sending N=%d", i) } close(output) }(ch) for i := 0; i < 7; i++ { val, ok := <-ch fmt.Printf("Recieved: %#v, %#v\n", val, ok) } ch <- fmt.Sprintf("where is your towel?") }
Помните ли как ви казахме, че range е нещо супер яко?
for, когато каналът бъде затворенfor val := range ch {
fmt.Printf("Recieved: %#v\n", val)
}
by Tony Hoare