var ch1 chan = make(chan int) // int类型的非缓冲通道
ch2 := make(chan int, 5) // int类型的缓冲通道
可将 channel 指定为单向通道。比如:
func receive(over chan<- bool) {
over <- true
}
1.After函数:起到定时器的作用,指定的纳秒后会向返回的channel中放入一个当前时间(time.Time)的实例。
//time.After() timeout
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan int)
go func() {
for i := 0; i < 10 ; i++ {
ch1 <- i
time.Sleep(1 * time.Second)
}
}()
timeout := time.After(5 * time.Second)
overTag := make(chan bool)
go func() {
for {
select {
case v1, ok := <- ch1:
if !ok {
overTag <- true
break
}
fmt.Printf("%s:%d \n", "CH1", v1)
case <- timeout:
fmt.Println("Timeout.")
overTag <- true
}
}
}()
<- overTag
fmt.Println("End.")
}
2.Tick函数:起到循环定时器的作用,每过指定的纳秒后都会向返回的channel中放入一个当前时间(time.Time)的实例
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan int)
go func() {
for i := 0; i < 5; i++ {
ch1 <- i
//time.Sleep(1 * time.Second)
}
close(ch1)
}()
//每1秒会将一个"当前时间"数据放入通道 tick中。(1秒取一次)
tick := time.Tick(1 * time.Second)
overTag := make(chan bool)
go func() {
for {
select {
case <-tick:
v, ok := <-ch1
if !ok {
overTag <- true
fmt.Println("Closed channel.")
break
}
fmt.Printf("%s: %d\n", "CH1", v)
}
}
}()
<-overTag
fmt.Println("End.")
}
3.Ticker结构:循环定时器。Tick函数就是包装它来完成功能的。该定时器可以被中止。
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan int)
//NewXxx(...)相当于Java中的工厂方法, 在Go中属于实例化 struct的惯用法,使用相当广泛
ticker := time.NewTicker(1 * time.Second)
go func() {
for {
select {
case <-ticker.C:
select {//select语句块也可以用在发送端,这 相当于每次随机选择一个case执行。
case ch1 <- 1:
case ch1 <- 2:
case ch1 <- 3:
}
//每次等待ticker的“事件”到来,限时2秒, 若超时则关闭ch1并结束该goroutine。
case <-time.After(2 * time.Second):
fmt.Println("Time out. Stopped ticker.")
close(ch1)
return
}
}
}()
overTag := make(chan bool)
go func() {
for {
select {
case v, ok := <-ch1:
if !ok {
fmt.Println("Closed channel.")
overTag <- true
break
}
fmt.Printf("%s: %d\n", "CH1", v)
}
}
}()
time.Sleep(5 * time.Second)
fmt.Println("Stop ticker.")
ticker.Stop()//5s停止
<-overTag
fmt.Println("End.")
}
默认情况下,调度器仅使用单线程,要想发挥多核处理器的并行处理能力,必须调用 runtime.GOMAXPROCS(n)来设置可并发的线程数,也可以通过设置环境变量 GOMAXPROCS 达到相同的目的
Gosched()让当前正在执行的 goroutine 放弃 CPU 执行权限,调度器安排其它正在等待的线程运行
runtime.Goexit()函数用于终止当前 goroutine,但 defer 函数将会被继续调用。
package main
import "fmt"
func producer(c chan<- int) {
defer close(c)
for i := 0; i < 10 ; i++ {
c <- i //阻塞,直到数据被消费者取走后才能发送下一条数据
}
}
func consumer(c <-chan int, f chan<- int) {
for {
if v, ok := <-c; ok {
fmt.Println(v) //阻塞,直到生产者放入数据后继续取数据
} else {
break
}
}
/* 或者
for v := range c {
fmt.Println(v)
}
*/
f <- 1 //向 F 发一个数据,告诉 main 数据已接收完成
}
func main() {
buf := make(chan int)
flg := make(chan int)
go producer(buf)
go consumer(buf, flg)
<-flg //等待数据接收完成
}
互斥锁:在读文件的时候,不能进行写入的操作,在写入时,不能进行读的操作。这就 是互斥锁。
读写锁:在读文件的时候,不能充许两个线程,同时读写,但如果两个线程同时读是没有问题的。只要在读的时候不要有写的线程。这就是读写锁
读写锁充许多个线程同时读,所以并 发性更好。读写锁具有以下特性: