Какво е интерфейс?
Как се създават нови типове?
type
type A struct { a int } type B struct { a float64 } type C struct { A B } var c C
Какво е c.a
?
Отговор:
- Компилатора ще ни каже грешка защото не знае кое a
имаме предвид.
- c.A.a
е int
- c.B.a
е float64
По какъв начин показваме, че тип имплементира интерфейс?
А как синхронизираме различните задачи?
#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) { printf("child sleeping...\n"); 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, NULL)) { 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 имаме Semaphores и Message passing
make
, като се подава типа, който ще се пренасяintChannel := make(chan int)
ch := make(chan []string, 100)
ch <- 64 read := <-ch
Операциите по изпращане и получаване се изпълняват с оператора <-
chan <- someValue
изпраща по каналаsomeVar, ok
= <-chan
получава от каналаSimple demo:
package main
import "fmt"
func main() { ch := make(chan string) go func() { fmt.Printf("Goroutine received: %s\n", <-ch) ch <- "Hello from the other side" }() ch <- "Hello, can you hear me?" fmt.Printf("Main received: %s", <-ch) }
Канал може да бъде затворен:
close(ch)
c := make(chan chan int)
func doSomething(input chan string) { // do something }
func doSomethingElse() chan string { result := make(chan string) return result }
Помните ли как ви казахме, че range
е нещо супер яко?
for
, когато каналът бъде затворенfor val := range ch { fmt.Printf("Recieved: %#v\n", val) }
<-chan
) или само за писане (chan<-
)package main
import (
"fmt"
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().Unix())
}
func randomFeed(count, max int) <-chan int { c := make(chan int) go func() { for i := 0; i < count; i++ { c <- rand.Intn(max) } close(c) }() return c } func main() { feed := randomFeed(10, 100) for v := range feed { fmt.Println(v) } }
package main
func main() { c := make(chan int) c <- 42 val := <-c println(val) }
Никога не използвайте неинициализиран канал!
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 }
package main
import (
"fmt"
"time"
)
func main() { c := make(chan int) go func() { fmt.Println("SCV: Reportin' for duty") time.Sleep(2 * time.Second) fmt.Println("SCV: Job's finished!") c <- 1 }() fmt.Println("Main does other time-consuming work...") time.Sleep(1 * time.Second) fmt.Println("Main is done") <-c fmt.Println("Everyone is done") }
var sem = make(chan struct{}, MaxOutstanding) func init() { for i := 0; i < MaxOutstanding; i++ { sem <- struct{}{} } } func handle(r *Request) { <-sem process(r) sem <- struct{}{} } func Serve(queue chan *Request) { for { req := <-queue go handle(req) } }
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?") }