forked from webtao520/golang_project
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
163 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package main | ||
|
||
import "fmt" | ||
|
||
func main() { | ||
// 创建一个整型的通道 | ||
ch := make(chan int) | ||
|
||
// 关闭通道 | ||
close(ch) | ||
|
||
// 打印通道的指针, 容量和长度 | ||
fmt.Printf("ptr:%p cap:%d len:%d\n", ch, cap(ch), len(ch)) | ||
|
||
// 给关闭的通道发送数据 | ||
ch <- 1 | ||
} | ||
|
||
/** | ||
代码运行后触发宕机: | ||
panic: send on closed channel | ||
代码说明如下: | ||
第 7 行,创建一个整型通道。 | ||
第 10 行,关闭通道,注意 ch 不会被 close 设置为 nil,依然可以被访问。 | ||
第 13 行,打印已经关闭通道的指针、容量和长度。 | ||
第 16 行,尝试给已经关闭的通道发送数据。 | ||
提示触发宕机的原因是给一个已经关闭的通道发送数据。 | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package main | ||
|
||
import "fmt" | ||
|
||
func main() { | ||
// 创建一个整型带两个缓冲的通道 | ||
ch := make(chan int, 2) | ||
|
||
// 给通道放入两个数据 | ||
ch <- 0 | ||
ch <- 1 | ||
|
||
// 关闭缓冲 | ||
close(ch) | ||
|
||
// 遍历缓冲所有数据, 且多遍历1个 | ||
for i := 0; i < cap(ch)+1; i++ { | ||
|
||
// 从通道中取出数据 | ||
v, ok := <-ch | ||
|
||
// 打印取出数据的状态 | ||
fmt.Println(v, ok) | ||
} | ||
} | ||
|
||
/** | ||
PS D:\goLang\github\golang_project\Go语言并发\Go语言关闭通道后继续使用通道> go run 2.go | ||
0 true | ||
1 true | ||
0 false | ||
代码说明如下: | ||
第 7 行,创建一个能保存两个元素的带缓冲的通道,类型为整型。 | ||
第 10 行和第11行,给这个带缓冲的通道放入两个数据。这时,通道装满了。 | ||
第 14 行,关闭通道。此时,带缓冲通道的数据不会被释放,通道也没有消失。 | ||
第 17 行,cap() 函数可以获取一个对象的容量,这里获取的是带缓冲通道的容量,也就是这个通道在 make 时的大小。虽然此时这个通道的元素个数和容量都是相同的,但是 cap 取出的并不是元素个数。这里多遍历一个元素,故意造成这个通道的超界访问。 | ||
第 20 行,从已关闭的通道中获取数据,取出的数据放在 v 变量中,类型为 int。ok 变量的结果表示数据是否获取成功。 | ||
第 23 行,将 v 和 ok 变量打印出来 | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
通道是一个引用对象,和 map 类似。map 在没有任何外部引用时,Go语言程序在运行时(runtime)会自动对内存进行垃圾回收(Garbage Collection, GC)。 | ||
类似的,通道也可以被垃圾回收,但是通道也可以被主动关闭。 | ||
|
||
### 格式 | ||
|
||
使用 close() 来关闭一个通道: | ||
close(ch) | ||
|
||
关闭的通道依然可以被访问,访问被关闭的通道将会发生一些问题。 | ||
|
||
### 给被关闭通道发送数据将会触发 panic | ||
|
||
被关闭的通道不会被置为 nil。如果尝试对已经关闭的通道进行发送,将会触发宕机,代码如下: | ||
+ 案例 | ||
* 1.go | ||
|
||
### 从已关闭的通道接收数据时将不会发生阻塞 | ||
|
||
从已经关闭的通道接收数据或者正在接收数据时,将会接收到通道类型的零值,然后停止阻塞并返回。 | ||
|
||
操作关闭后的通道: | ||
+ 案例 | ||
* 2.go | ||
|
||
|
||
运行结果前两行正确输出带缓冲通道的数据,表明缓冲通道在关闭后依然可以访问内部的数据。 | ||
|
||
运行结果第三行的“0 false”表示通道在关闭状态下取出的值。0 表示这个通道的默认值,false 表示没有获取成功,因为此时通道已经空了。 | ||
我们发现,在通道关闭后,即便通道没有数据,在获取时也不会发生阻塞,但此时取出数据会失败。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package main | ||
import ( | ||
"fmt" | ||
"runtime" | ||
) | ||
func main() { | ||
cpuNum := runtime.NumCPU() //获得当前设备的cpu核心数 | ||
fmt.Println("cpu核心数:", cpuNum) | ||
runtime.GOMAXPROCS(cpuNum) //设置需要用到的cpu数量 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
Go语言具有支持高并发的特性,可以很方便地实现多线程运算,充分利用多核心 cpu 的性能。 | ||
|
||
众所周知服务器的处理器大都是单核频率较低而核心数较多,对于支持高并发的程序语言, | ||
|
||
可以充分利用服务器的多核优势,从而降低单核压力,减少性能浪费。 | ||
|
||
Go语言实现多核多线程并发运行是非常方便的,下面举个例子: | ||
+ 案例 | ||
* 1.go |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"sync/atomic" | ||
) | ||
|
||
var ( | ||
// 序列号 | ||
seq int64 | ||
) | ||
|
||
// 序列号生成器 | ||
func GenID () int64 { | ||
// 尝试原子的增加序列号 | ||
// 根据 atomic.AddInt64() 的参数声明,这个函数会将修改后的值以返回值方式传出。下面代码对加粗部分进行了修改: | ||
return atomic.AddInt64(&seq, 1) | ||
//return seq | ||
} | ||
|
||
func main(){ | ||
//生成10个并发序列号 | ||
for i := 0; i < 10; i++ { | ||
go GenID() | ||
} | ||
fmt.Println(GenID()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
Go语言程序可以使用通道进行多个 goroutine 间的数据交换,但这仅仅是数据同步中的一种方法。 | ||
通道内部的实现依然使用了各种锁,因此优雅代码的代价是性能。在某些轻量级的场合, | ||
原子访问(atomic包)、互斥锁(sync.Mutex)以及等待组(sync.WaitGroup)能最大程度满足需求。 | ||
|
||
本节只讲解原子访问,互斥锁和等待组将在接下来的两节中讲解。 | ||
|
||
当多线程并发运行的程序竞争访问和修改同一块资源时,会发生竞态问题。 | ||
|
||
下面的代码中有一个 ID 生成器,每次调用生成器将会生成一个不会重复的顺序序号,使用 10 个并发生成序号,观察 10 个并发后的结果。 | ||
|
||
竞态检测的具体代码: | ||
+ 案例 | ||
* 1.go | ||
|
||
没有发生竞态问题,程序运行正常。 | ||
|
||
本例中只是对变量进行增减操作,虽然可以使用互斥锁(sync.Mutex)解决竞态问题,但是对性能消耗较大。 | ||
在这种情况下,推荐使用原子操作(atomic)进行变量操作。 |