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实现生产者消费者模式。