1、go语言中goroute之间通信有两种方式:

  • 通过全局变量,这种方式得加锁
  • 通过channel进行通信

下面是一个通过全局变量进行通信的例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package main

import (
	"fmt"
	"sync"
	"time"
)

var (
	m    = make(map[int]uint64)
	lock sync.Mutex
)

type task struct {
	n int
}

func calc(t *task) {
	var sum uint64
	sum = 1
	for i := 1; i < t.n; i++ {
		sum *= uint64(i)
	}
	lock.Lock()
	m[t.n] = sum
	lock.Unlock()
}

func main() {
	for i := 0; i < 20; i++ {
		t := &task{n: i}
		go calc(t)
	}
	time.Sleep(10 * time.Second)

	lock.Lock()
	for k, v := range m {
		fmt.Printf("%d!=%v\n", k, v)
	}
	lock.Unlock()

}

输出结果如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
0!=1
7!=720
11!=3628800
5!=24
14!=6227020800
16!=1307674368000
18!=355687428096000
13!=479001600
19!=6402373705728000
1!=1
9!=40320
10!=362880
4!=6
2!=1
3!=2
12!=39916800
8!=5040
6!=120
15!=87178291200
17!=20922789888000</pre>

2、理解go中的并发

a、可以看到通过关键字go,运行的时候不是串行执行的,使用go,起了多个goroute。由于map是无序的,排除map的没有顺序,修改如下,直接打印出来,看的可能更清楚一点;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package main

import (
	"fmt"
	"sync"
)

var (
	m    = make(map[int]uint64)
	lock sync.Mutex
)

type task struct {
	n int
}

func calc(t *task) {
	var sum uint64
	sum = 1
	for i := 1; i &lt; t.n; i++ {
		sum *= uint64(i)
	}
	fmt.Println(t.n, sum)
	lock.Lock()
	m[t.n] = sum
	lock.Unlock()
}

func main() {
	for i := 0; i &lt; 20; i++ {
		t := &task{n: i}
		go calc(t)
	}
	// time.Sleep(10 * time.Second)

	// lock.Lock()
	// for k, v := range m {
	// 	fmt.Printf("%d!=%v\n", k, v)
	// }
	// lock.Unlock()

}

输出结果如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
1 1
3 2
2 1
4 6
5 24
13 479001600
7 720
6 120
15 87178291200
9 40320
10 362880
8 5040
14 6227020800
16 1307674368000
18 355687428096000
12 39916800
11 3628800
17 20922789888000
19 6402373705728000
0 1

b、如果go没有关键字,也就是没有启动多个goroute的话,应该只是在main函数的那个goroute里面串行执行的,去掉go;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package main

import (
	"fmt"
	"sync"
	"time"
)

var (
	m    = make(map[int]uint64)
	lock sync.Mutex
)

type task struct {
	n int
}

func calc(t *task) {
	var sum uint64
	sum = 1
	for i := 1; i &lt; t.n; i++ {
		sum *= uint64(i)
	}
	fmt.Println(t.n, sum)
	lock.Lock()
	m[t.n] = sum
	lock.Unlock()
}

func main() {
	for i := 0; i &lt; 20; i++ {
		t := &task{n: i}
		calc(t)
	}
	time.Sleep(10 * time.Second)

	// lock.Lock()
	// for k, v := range m {
	// 	fmt.Printf("%d!=%v\n", k, v)
	// }
	// lock.Unlock()

}

没有go关键字,执行结果如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
0 1
1 1
2 1
3 2
4 6
5 24
6 120
7 720
8 5040
9 40320
10 362880
11 3628800
12 39916800
13 479001600
14 6227020800
15 87178291200

上面也可以看到,go的并发是通过go关键字来实现的,main函数本身会启动一个goroute,如果我们使用go关键字,是会启动新的goroute,它是和main函数的goroute并发进行的,但如果main函数的goroute结束了,整个程序就结束了,所以我们等待了10m。