网站的模板演示怎么做,wordpress下载付费,想学手艺在哪里可以培训,学校网站开发与设计目录
一、什么是channel
二、为什么要有channel
三、channel操作使用
初始化
操作
单向channel
双向channel#xff0c;可读可写
四、close下什么场景会出现panic
五、总结 一、什么是channel Channels are a typed conduit through which you can send and receive …目录
一、什么是channel
二、为什么要有channel
三、channel操作使用
初始化
操作
单向channel
双向channel可读可写
四、close下什么场景会出现panic
五、总结 一、什么是channel Channels are a typed conduit through which you can send and receive values with the channel operator, -. channel是go语言的核心类型之一翻译为中文是“通道管道”为了实现协程间的同步与通信。遵循FIFO(先进先出)的队列保证线程安全。 二、为什么要有channel “不要用共享内存来通信而是使用通信来共享内存” -- go语言并发哲学 任何一种程序语言要实现并发能力就要做好多线程之间的协调工作让彼此知道对方状态获取对方的信息完成预定任务。大多数的编程语言的并发编程模型是基于线程和内存同步访问控制go语言的并发编程的模型则用 goroutine 和 channel 来实现。channel是goroutine之间架了一条管道在管道里传输数据实现goroutine间的通信来协调工作当然goroutine实现通信不止channel一种还有 go语言中协程实现通信的三种方式 context\sync.cond\channel。 在go语言中CSP(Communicating Sequential Processes)模型是go语言并发编程哲学的实现三种线程模型与CSP实现goroutine与channel是CSP上层实现的两大基石。 channel的底层实现保证了协程操作安全在任何同一时间内channel中的一个数据只允许一个协程访问不存在数据竞争。
三、channel操作使用
初始化
channel是引用类型有带缓冲channel和无缓冲channel未初始化的channel值是nil。通过内建函数make (仅对map\slice\channel初始化)分配内存并初始化。 操作
channel只有三种操作方式Send、Receive、close。
通过操作符 - 实现发送或读取数据中文社区更愿意把Send和接收从通信操作符号看chan - 是发送数据到chan- chan是接收chan中数据这是从通信角度理解。从读写角度理解我更愿意翻译为chan - 为写入数据到chan-chan为从chan读取数据出来。数据为go中任意类型 close为关闭chanclose(chan) 虽然go语言采自动垃圾回收机制来管理内存但go的垃圾回收器不会主动回收运行中的channel 主动关闭channel为了防止内存泄露。 单向channel
单向channel分为write-only,read-only channel主要作用有限制通信方向、减少竞态条件、提高代码可读性。 限制通信方向使用只写通道可以在某些情况下限制通信的方向确保特定的协程只能发送数据到通道而不会在不适当的地方进行接收操作。这有助于清晰地定义协程之间的职责和交互。 减少竞态条件当只有一个协程负责向通道发送数据而其他协程只负责接收时可以减少竞态条件的出现。这有助于避免数据竞争和复杂的同步问题。 提高代码可读性通过使用只写通道你可以在代码中清楚地表达协程的作用。这有助于其他开发人员更容易地理解代码并阅读文档。
unc worker(id int, jobs -chan int, results chan- int) {for job : range jobs {fmt.Printf(Worker %d started job %d\n, id, job)time.Sleep(time.Millisecond)fmt.Printf(Worker %d finished job %d\n, id, job)results - job * 2}
}func main() {numJobs : 5jobs : make(chan int, numJobs)results : make(chan int, numJobs)// 启动3个工作协程for i : 1; i 3; i {go worker(i, jobs, results)}// 向通道发送任务for j : 1; j numJobs; j {jobs - j}close(jobs)// 收集结果for r : 1; r numJobs; r {result : -resultsfmt.Println(Result:, result)}
}
在这个示例中我们使用只写通道 chan- 来传递任务给工作协程工作协程的- chan只负责从通道中接收任务。这种模式将任务分发和执行解耦增加了代码的可读性和可维护性。
总之单向channel在go语言中用于限制通道的使用方向有助于提高代码的可读性、降低竞态条件和减少复杂性。
双向channel可读可写
基本通道使用创建一个通道发送数据到通道然后从通道接收数据
func base() {ch : make(chan int) // 创建一个通道go func() {ch - 42 // 发送数据到通道}()value : -ch // 从通道接收数据fmt.Println(Received:, value) // Received: 42
}
使用缓冲通道创建带有缓冲区的通道可以存储多个数据然后使用循环向通道发送和接收数据。
func cacheChan() {ch : make(chan int, 2) // 创建一个容量为2的缓冲通道ch - 1ch - 2value1 : -chvalue2 : -chfmt.Println(Received:, value1, value2) // Received: 1 2
}
协程池 使用通道来实现一个简单的协程池从通道中获取任务并分发给协程进行处理。
func worker(id int, jobs -chan int, results chan- int) {for job : range jobs {fmt.Printf(Worker %d started job %d\n, id, job)time.Sleep(time.Millisecond)fmt.Printf(Worker %d finished job %d\n, id, job)results - job * 2}
}func goroutinePool() {numJobs : 5numWorkers : 3jobs : make(chan int, numJobs)results : make(chan int, numJobs)for i : 1; i numWorkers; i {go worker(i, jobs, results)}for j : 1; j numJobs; j {jobs - j}close(jobs)var wg sync.WaitGroupwg.Add(numJobs)go func() {wg.Wait()close(results)}()for r : range results {fmt.Println(Result:, r)wg.Done()}
}
取消协程 使用通道来实现协程的取消通过发送信号告知协程停止工作。
func worker(cancel -chan struct{}) {for {select {case -cancel:fmt.Println(Worker canceled)returndefault:fmt.Println(Working...)time.Sleep(time.Second)}}
}func cancelRoutine() {cancel : make(chan struct{})go worker(cancel)time.Sleep(3 * time.Second)fmt.Println(Canceling worker...)close(cancel)time.Sleep(1 * time.Second)
} 四、close下什么场景会出现panic
在使用channel时为了获得良好的协程同步与通信结果在一些场景下会导致程序panic
如下为读写与channel状态对协程的影响表 调用close关闭channel时未初始化时关闭、重复关闭、关闭后发送、发送时关闭在这四种情况下会出现panic 未初始化就关闭
func main() {var ch chan intclose(ch) // panic: close of nil channel
} 重复关闭
func main() {ch : make(chan int)close(ch)close(ch) // panic: close of closed channel
} 关闭后发送
func main() {wg : sync.WaitGroup{}wg.Add(1)ch : make(chan int)close(ch)go func() {defer wg.Done()ch - 1 // panic: send on closed channel}()-chwg.Wait()
} 发送后关闭
func main() {ch : make(chan int)var wg sync.WaitGroupwg.Add(1)go func() {defer wg.Done()defer fmt.Println(close ch) // close chdefer close(ch)go func() {ch - 1 // panic: send on closed channel}()}()fmt.Println(-ch)wg.Wait()
}
不正确地关闭channel会导致程序panic如何优雅关闭channel呢
参看《How to Gracefully Close Channels》
五、总结 本内容主要讲述了channel的基础知识包括定义、使用背景、类型、操作方式、使用场景、不正确关闭channel会panic的场景。没有对channel的底层实现原理进行解读参看channel的底层实现原理了解。