Skip to content

Commit b5098c9

Browse files
committed
concurrency examples.
1 parent 8c23d71 commit b5098c9

File tree

8 files changed

+283
-0
lines changed

8 files changed

+283
-0
lines changed

examples/concurrency/crawler.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// concurrent web crawler
2+
// Adopted from the example from "The Go Programming Language"
3+
package main
4+
5+
import (
6+
"log"
7+
"os"
8+
9+
"gopl.io/ch5/links"
10+
)
11+
12+
var done = make(chan bool)
13+
//var rateLimiter = make(chan int, 4)
14+
15+
// visits given URL and returns all the links present in that page
16+
func crawl(url string) []string {
17+
//rateLimiter <- 0
18+
log.Println(url)
19+
20+
links, err := links.Extract(url)
21+
22+
//<-rateLimiter
23+
24+
if err != nil {
25+
log.Print(err) // print error and ignore
26+
}
27+
return links
28+
}
29+
30+
func startCrawler(worklist chan string) {
31+
visited := make(map[string]bool)
32+
33+
for link := range worklist {
34+
if visited[link] {
35+
continue // skip already visited pages
36+
}
37+
visited[link] = true // mark as visited
38+
39+
// passing link as argument is very important here.
40+
// If we don't do that then the function will pick the value of link
41+
// at the time of running, not at the time of starting this
42+
// function. Since the loop variable `link` is changing in every
43+
// iteration, it is important to pass a copy of that to the
44+
// goroutine
45+
go func(link string) {
46+
newLinks := crawl(link)
47+
for _, newLink := range newLinks {
48+
worklist <- newLink
49+
}
50+
}(link)
51+
}
52+
}
53+
54+
func main() {
55+
worklist := make(chan string)
56+
go startCrawler(worklist)
57+
58+
worklist <- os.Args[1]
59+
60+
<-done
61+
}

examples/concurrency/display.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"time"
6+
)
7+
8+
func display(name string, n int) {
9+
for i := 0; i < n; i++ {
10+
fmt.Printf("%d: %s\n", i, name)
11+
}
12+
}
13+
14+
func main() {
15+
go display("A", 10)
16+
display("B", 10)
17+
18+
// hack to wait till the goroutine finished
19+
time.Sleep(1 * time.Second)
20+
}

examples/concurrency/display_v2.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
func display(name string, n int, done chan bool) {
8+
for i := 0; i < n; i++ {
9+
fmt.Printf("%d: %s\n", i, name)
10+
}
11+
done <- true
12+
}
13+
14+
func main() {
15+
done := make(chan bool)
16+
17+
go display("A", 10, done)
18+
go display("B", 10, done)
19+
go display("C", 10, done)
20+
21+
// receive something from the channel. blocks until someone sends it
22+
<-done
23+
<-done
24+
<-done
25+
}

examples/concurrency/echoserver.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"io"
7+
"log"
8+
"net"
9+
)
10+
11+
func handleConn(c net.Conn) {
12+
defer c.Close()
13+
14+
input := bufio.NewScanner(c)
15+
for input.Scan() {
16+
echo(c, input.Text())
17+
}
18+
}
19+
20+
func echo(c net.Conn, msg string) {
21+
_, err := io.WriteString(c, msg+"\n")
22+
if err != nil {
23+
log.Print("err") // connection failed
24+
}
25+
}
26+
27+
func main() {
28+
// start listening on port 8000
29+
listener, err := net.Listen("tcp", "localhost:8000")
30+
if err != nil {
31+
log.Fatal(err)
32+
}
33+
fmt.Println("started server on localhost:8000")
34+
35+
for {
36+
conn, err := listener.Accept()
37+
if err != nil {
38+
log.Print("err") // connection failed
39+
continue
40+
}
41+
go handleConn(conn)
42+
}
43+
}

examples/concurrency/helloserver.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"log"
7+
"net"
8+
"time"
9+
)
10+
11+
func handleConn(c net.Conn) error {
12+
defer c.Close()
13+
_, err := io.WriteString(c, "Hello from Server!\n")
14+
if err != nil {
15+
return err
16+
}
17+
time.Sleep(5 * time.Second)
18+
_, err = io.WriteString(c, "Bye from Server!\n")
19+
if err != nil {
20+
return err
21+
}
22+
return nil
23+
}
24+
25+
func main() {
26+
// start listening on port 8000
27+
listener, err := net.Listen("tcp", "localhost:8000")
28+
if err != nil {
29+
log.Fatal(err)
30+
}
31+
fmt.Println("started server on localhost:8000")
32+
33+
for {
34+
conn, err := listener.Accept()
35+
if err != nil {
36+
log.Print("err") // connection failed
37+
continue
38+
}
39+
go handleConn(conn)
40+
}
41+
}

examples/concurrency/netcat.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package main
2+
3+
import (
4+
"io"
5+
"log"
6+
"net"
7+
"os"
8+
)
9+
10+
func mustCopy(dst io.Writer, src io.Reader) {
11+
if _, err := io.Copy(dst, src); err != nil {
12+
log.Fatal(err)
13+
}
14+
}
15+
16+
func main() {
17+
host := os.Args[1]
18+
port := os.Args[2]
19+
conn, err := net.Dial("tcp", host+":"+port)
20+
if err != nil {
21+
log.Fatal(err)
22+
}
23+
defer conn.Close()
24+
go mustCopy(os.Stdout, conn)
25+
mustCopy(conn, os.Stdin)
26+
}

examples/concurrency/pipeline.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package main
2+
3+
import "fmt"
4+
5+
func numbers(n int) <-chan int {
6+
c := make(chan int)
7+
go func() {
8+
for i := 0; i < n; i++ {
9+
c <- i
10+
}
11+
close(c)
12+
}()
13+
return c
14+
}
15+
16+
func squares(seq <-chan int) <-chan int {
17+
c := make(chan int)
18+
go func() {
19+
for n := range seq {
20+
c <- n * n
21+
}
22+
close(c)
23+
}()
24+
return c
25+
}
26+
27+
func printer(seq <-chan int) {
28+
for n := range seq {
29+
fmt.Println(n)
30+
}
31+
}
32+
33+
func main() {
34+
n := numbers(10)
35+
sq := squares(n)
36+
printer(sq)
37+
}

examples/concurrency/race.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"sync"
6+
)
7+
8+
var sum int
9+
var lock sync.Mutex
10+
11+
func compute(n int, w *sync.WaitGroup) {
12+
for i := 0; i < n; i++ {
13+
//lock.Lock()
14+
sum++
15+
//lock.Unlock()
16+
}
17+
w.Done()
18+
}
19+
20+
func main() {
21+
var w sync.WaitGroup
22+
23+
w.Add(3)
24+
n := 100000
25+
go compute(n, &w)
26+
go compute(n, &w)
27+
go compute(n, &w)
28+
w.Wait()
29+
fmt.Println("sum =", sum)
30+
}

0 commit comments

Comments
 (0)