1.go语言并发优势
2.并发小程序
3.runtime包使用
4.channel使用
一、go语言并发优势
并发就是单核cpu通过时间片轮转,“同时”处理多个任务。并发是现代程序设计非常重要的一个环节,而go语言在语言层面支持高并发,一个普通的计算机就能支持上万个goroutine竞争资源。同时代码实现简单,开发效率高。
二、go语言并发demo
package main
import "fmt"
import "time"
func sayHello(id int) {
//每隔两秒打印一次
for i := 0; i < 5; i++ {
fmt.Println("Hello ", id)
time.Sleep(time.Second * 2)
}
}
func main() {
for i := 0; i < 10; i++ {
//开启一个goroutine,每个两秒打印一个数字
go sayHello(i)
}
//使主goroutine不会退出
for {
}
}
在没有使用并发时,程序会一句一句的打印,使用并发之后程序会十个十个的打印五次。最后的for循环为了使主协程不会在执行完毕后推出,否则主协退出子协程没来得及打印将不会看到效果。
三、runtime包使用
runtime.Gosched(),让出时间片。
package main
import "fmt"
import "runtime"
func newTask() {
for i := 0; i < 5; i++ {
fmt.Println("go")
}
}
func main() {
go newTask()
//正常情况下主协程执行完毕之后,子协程未来得及调用,调用runtime.Gosched()方法后,主协程让出时间片,子协程先执行完
runtime.Gosched()
fmt.Println("hello")
}
打印结果为:
go
go
go
go
go
hello
runtime.Goexit(),终止协程。
在上面代码中加入runtime.Goexit(),使子协程打印三次之后中断。
package main
import "fmt"
import "runtime"
func newTask() {
for i := 0; i < 5; i++ {
fmt.Println("go")
if i == 2 {
runtime.Goexit()
}
}
}
func main() {
go newTask()
//正常情况下主协程执行完毕之后,子协程未来得及调用,调用runtime.Gosched()方法后,主协程让出时间片,子协程先执行完
runtime.Gosched()
fmt.Println("hello")
}
打印结果为:
go
go
go
hello
runtime.GOMAXPROCS()方法可以设置使用cpu核数,默认情况下cpu所有核都在工作。
package main
import "fmt"
import "runtime"
func main() {
//设置工作cpu两核
n := runtime.GOMAXPROCS(2)
fmt.Print(n)
for {
go fmt.Print(1)
fmt.Print(0)
}
}
运行结果可以看出,cpu核数越少,0和1将会大面积打印。
四、channel使用
1.使用channel实现同步。子协程执行完毕后主协程再结束。
package main
import "fmt"
func main() {
//定义一个channel
ch := make(chan string)
defer fmt.Println("主协程执行完毕!!!!")
go func() {
defer fmt.Println("子协程执行完毕!!!!")
for i := 0; i < 5; i++ {
fmt.Println("Hello i = ", i)
}
ch <- "Hello World"
}()
str := <-ch
fmt.Println("子协程发来消息:", str)
}
2.无缓冲的channel只要数据未被取出程序就会阻塞,有缓冲的channel在缓冲放满之后程序阻塞。
使用range遍历channel;
package main
import "fmt"
func main() {
//定义一个channel
ch := make(chan string, 2)
go func() {
for i := 0; i < 5; i++ {
fmt.Println("Hello i = ", i)
ch <- "Hello"
}
//不需要读写是关闭channel
close(ch)
}()
for str := range ch {
fmt.Println("子协程发来消息:", str)
}
}
代码中设置了channel的缓冲为2,当没有缓冲时,程序打印结果;
Hello i = 0
Hello i = 1
子协程发来消息: Hello
子协程发来消息: Hello
Hello i = 2
Hello i = 3
子协程发来消息: Hello
子协程发来消息: Hello
Hello i = 4
子协程发来消息: Hello
加入缓冲后,程序打印结果:
Hello i = 0
Hello i = 1
Hello i = 2
Hello i = 3
子协程发来消息: Hello
子协程发来消息: Hello
子协程发来消息: Hello
子协程发来消息: Hello
Hello i = 4
子协程发来消息: Hello
3.单向channel使用
package main
import "fmt"
//只负责向channel中放数据
func producter(out chan<- int) {
for i := 0; i < 10; i++ {
out <- i
}
close(out)
}
//只负责从channel中取数据
func customer(in <-chan int) {
for data := range in {
fmt.Println("Hello :", data)
}
}
func main() {
ch := make(chan int)
go producter(ch)
customer(ch)
}使用单向channel实现生产者消费者模式。