本节内容:Lect 2 RPC and Threads
线程:Threads allow one program to (logically) execute many things at once.
The threads share memory. However, each thread includes some per-thread state: program counter, registers, stack.
下面以go语言写一个爬虫作为例子来介绍线程:
Go example: crawler.go
package main import ( "fmt" "sync" ) // // Several solutions to the crawler exercise from the Go tutorial // https://tour.golang.org/concurrency/10 // // // Serial crawler // func Serial(url string, fetcher Fetcher, fetched map[string]bool) { if fetched[url] { return } fetched[url] = true urls, err := fetcher.Fetch(url) if err != nil { return } for _, u := range urls { Serial(u, fetcher, fetched) } return } // // Concurrent crawler with shared state and Mutex // type fetchState struct { mu sync.Mutex fetched map[string]bool } func ConcurrentMutex(url string, fetcher Fetcher, f *fetchState) { f.mu.Lock() if f.fetched[url] { f.mu.Unlock() return } f.fetched[url] = true f.mu.Unlock() urls, err := fetcher.Fetch(url) if err != nil { return } var done sync.WaitGroup for _, u := range urls { done.Add(1) go func(u string) { defer done.Done() ConcurrentMutex(u, fetcher, f) }(u) } done.Wait() return } func makeState() *fetchState { f := &fetchState{} f.fetched = make(map[string]bool) return f } // // Concurrent crawler with channels // func worker(url string, ch chan []string, fetcher Fetcher) { urls, err := fetcher.Fetch(url) if err != nil { ch <- []string{} } else { ch <- urls } } func master(ch chan []string, fetcher Fetcher) { n := 1 fetched := make(map[string]bool) for urls := range ch { for _, u := range urls { if fetched[u] == false { fetched[u] = true n += 1 go worker(u, ch, fetcher) } } n -= 1 if n == 0 { break } } } func ConcurrentChannel(url string, fetcher Fetcher) { ch := make(chan []string) go func() { ch <- []string{url} }() master(ch, fetcher) } // // main // func main() { fmt.Printf("=== Serial===\n") Serial("http://golang.org/", fetcher, make(map[string]bool)) fmt.Printf("=== ConcurrentMutex ===\n") ConcurrentMutex("http://golang.org/", fetcher, makeState()) fmt.Printf("=== ConcurrentChannel ===\n") ConcurrentChannel("http://golang.org/", fetcher) } // // Fetcher // type Fetcher interface { // Fetch returns a slice of URLs found on the page. Fetch(url string) (urls []string, err error) } // fakeFetcher is Fetcher that returns canned results. type fakeFetcher map[string]*fakeResult type fakeResult struct { body string urls []string } func (f fakeFetcher) Fetch(url string) ([]string, error) { if res, ok := f[url]; ok { fmt.Printf("found: %s\n", url) return res.urls, nil } fmt.Printf("missing: %s\n", url) return nil, fmt.Errorf("not found: %s", url) } // fetcher is a populated fakeFetcher. var fetcher = fakeFetcher{ "http://golang.org/": &fakeResult{ "The Go Programming Language", []string{ "http://golang.org/pkg/", "http://golang.org/cmd/", }, }, "http://golang.org/pkg/": &fakeResult{ "Packages", []string{ "http://golang.org/", "http://golang.org/cmd/", "http://golang.org/pkg/fmt/", "http://golang.org/pkg/os/", }, }, "http://golang.org/pkg/fmt/": &fakeResult{ "Package fmt", []string{ "http://golang.org/", "http://golang.org/pkg/", }, }, "http://golang.org/pkg/os/": &fakeResult{ "Package os", []string{ "http://golang.org/", "http://golang.org/pkg/", }, }, }
RPC
基本概念5105都学过了.....
下面以go语言写的简易key-value storage为例:
扫描二维码关注公众号,回复:
6838735 查看本文章
Go example: kv.go
package main import ( "fmt" "log" "net" "net/rpc" "sync" ) // // RPC request/reply definitions // const ( OK = "OK" ErrNoKey = "ErrNoKey" ) type Err string type PutArgs struct { Key string Value string } type PutReply struct { Err Err } type GetArgs struct { Key string } type GetReply struct { Err Err Value string } // // Client // func connect() *rpc.Client { client, err := rpc.Dial("tcp", ":1234") if err != nil { log.Fatal("dialing:", err) } return client } func get(key string) string { client := connect() args := GetArgs{"subject"} reply := GetReply{} err := client.Call("KV.Get", &args, &reply) if err != nil { log.Fatal("error:", err) } client.Close() return reply.Value } func put(key string, val string) { client := connect() args := PutArgs{"subject", "6.824"} reply := PutReply{} err := client.Call("KV.Put", &args, &reply) if err != nil { log.Fatal("error:", err) } client.Close() } // // Server // type KV struct { mu sync.Mutex data map[string]string } func server() { kv := new(KV) kv.data = map[string]string{} rpcs := rpc.NewServer() rpcs.Register(kv) l, e := net.Listen("tcp", ":1234") if e != nil { log.Fatal("listen error:", e) } go func() { for { conn, err := l.Accept() if err == nil { go rpcs.ServeConn(conn) } else { break } } l.Close() }() } func (kv *KV) Get(args *GetArgs, reply *GetReply) error { kv.mu.Lock() defer kv.mu.Unlock() val, ok := kv.data[args.Key] if ok { reply.Err = OK reply.Value = val } else { reply.Err = ErrNoKey reply.Value = "" } return nil } func (kv *KV) Put(args *PutArgs, reply *PutReply) error { kv.mu.Lock() defer kv.mu.Unlock() kv.data[args.Key] = args.Value reply.Err = OK return nil } // // main // func main() { server() put("subject", "6.824") fmt.Printf("Put(subject, 6.824) done\n") fmt.Printf("get(subject) -> %s\n", get("subject")) }
Ref:
https://golang.org/doc/effective_go.html
https://golang.org/pkg/net/rpc/
https://tour.golang.org/concurrency/10
https://www.cnblogs.com/pdev/p/10936485.html