Golang 通道的特点为以下几点:
1、如果是接收(RX)
1.1、如果通道是无缓冲的,接收操作只有在有其他 goroutine 发送数据到通道时才会成功,否则会阻塞。
1.2、如果通道是有缓冲的,接收操作只有在通道缓冲区有数据时才会成功,否则会阻塞。
2、如果是写入(TX)
2.1、如果通道是无缓冲的(即容量为0),发送操作会阻塞直到有其他 goroutine 准备好接收这个数据。
2.2、如果通道是有缓冲的(即容量大于0),发送操作只有在通道缓冲区已满时才会阻塞,否则会立即完成。
了解 TAP(基于任务模式的异步编程模型)的同学很容易理解这套模型。
Golang 像 C/C++ 20、C# 4.5 语言之中,我们需要在另一个协同程序之中等待某个 “stackless 无栈协同子程序” 的输出结果。
以 Microsoft Virual C# 为例子:
TaskCompletionSource.SetResult() // 管道输入
await TaskCompletionSource.Task
TaskCompletionSource.Task.Result // 管道输出
它们其实都差不多的,只是 C# 的实现,代码会多点,C/C++ 会更多点,但大家都可以实现,但比 Golang 会繁琐很多,但其优点是更为可控(这点在大型且复杂的项目之中很重要)。
只是区别是输入这部分,其它语言并未提供类似的机制,但我们可以通过在调用协同程序的时候传入特定参数来表示输入,但如果需要模拟这套机制并不复杂,如模拟管道读入。
我们只需要使用 AutoResetEvent 进行同步即可轻松实现,当然如果要考虑TX/RX缓冲区,从实现上来说这个也并不复杂。
在 Golang 之中,永久阻塞协程,可以执行该条命令:
<-make(chan struct{})
其作用为等待空白 chan 的输出,但由于没有任何地方可以向管道输入数据,所以会无限制阻塞该协同程序,当然写法上也不一定仅用该方法。
但这类代码执行,想要退出就只有一个办法,调用 os.Exit(exitCode) 命令关闭当前的进程才可以退出该协程的运行。
运算符:<-
在 Golang 之中向管道输入:
管道变量 <- 数据
在 Golang 之中向变量输出:
数据 <- 管道变量
本人对于 Golang 用起来不是太顺手,不太快乐,主要是以下几个点:
1、无原生指针(intptr,这个是无可奈何地办法)
2、语言规范要求太死,格式化四个空格捣鼓半天还是不成(制表符)
3、没有模板(泛型)
4、内存不可控制,.NET 可以显示GC回收及控制GC类型,Golang 是一点解决方案都无
5、没有析构函数
6、没有线程概念
我本人更喜欢 “多线程+协程” 全部可控,自行决定、评估合适采用协程,编程语言要提供最强的灵活性,但这或许在今时今日会是一个老古董的想法了。
7、过度依赖于IDE
例如:
过度的类型推导,Golang 之中可以大量的类型推导,即匿名变量声明,在vim、notepad++、sublime 等这些环境之中有时候真的会很困惑。
其它的不在此处累赘,每个语言都有其优点及适用场景,本文也不是来批评编程语言的,这没有意义,工具存在自然有其存在的意义,作为开发人员的我们,只需要那这些语言实现我们期望的一切即可,但也需要考量成本及多方因素。
就像我们可以用 C/C++ 解决现代计算机几乎所有的问题,如果我们使用 C/C++ 不可以解决,那么我们就可以写 .S、.ASM 或者内嵌汇编代码来解决问题,如果汇编也不能解决,那么这个问题就不是你我可以解决的,那么就交给其它人或者未来的人们去解决把。
不曾否认 Golang 语言的优点,简单,就是塔喵滴简单,在现代这个浮躁的中国大陆技术界,招募年轻人新鲜血液来说,Golang 这类型编程语言,显然更容易的多,大家都是一群草台班子,普通的人们,除了装X,一无是处。
一个或许未来会发生的现实,也许未来的新生代开发人员,在学校学习时,在也不会在接触汇编、再也不会接触 C 语言,Golang、Rust 这些语言成为教材上面,引领学生初步学习,乃至入门的编程语言,想想,也许,还挺可怕的。
package main
import (
"fmt"
"os"
"os/signal"
)
func main() {
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
signal := make(chan os.Signal, 1)
go func() {
fmt.Println("程序即将关闭...")
// 在这里执行你的自定义操作
fmt.Println("执行自定义操作完成")
// os.Exit(0)
signal <- <-stop
}()
fmt.Println("按下 Control+C 或关闭控制台窗口以退出程序")
// <-make(chan struct{})
fmt.Println("信号:", <-signal)
}