理解Go语言并发编程


并发编程综述

有一定软件开发经验的人都应该知道并发编程。并发编程是一种现代计算机编程技术。它的含义比较宽泛,可以是多线程编程,也可以是多进程编程,还可以是编写分布式程序。Go 最明显的优势在于拥有基于多线程的并发编程方式。不过在多进程和分布式程序的编写方面,由于它具有高效的并发编程方法以及便捷的标准库,我们总能事半功倍。

并发编程基础

并发这个概念由来已久,其主要思想是使多个任务可以在同一个时间段内执行以便能够更快地得到结果。在计算机问世不久,并发的概念就出现了。

并发编程的思想来自于多任务操作系统,它允许同时运行多个程序。在早期的单用户操作系统中,任务是一个接一个运行的,各个任务的执行完全是串行的。只有在一个任务运行完成之后,另一个任务才会被读取。而多任务操作系统则允许终端用户同时运行多个程序。当一个程序暂时不需要使用 CPU 的时候,系统会把该程序挂起或中断,以使其他程序可以使用 CPU。

最早支持并发编程的计算机编程语言是汇编语言。不过那时并没有任何理论基础来支持这种编程方式,这样一个细微的编程错误就会使程序变得非常不稳定,并且对这种程序的测试也是几乎不可能的。

在20世纪 60年代末,多任务操作系统已变得非常雕肿和脆弱。对系统资源的无限制抢夺成为程序死锁现象频繁发生的导火索。连多任务操作系统的缔造者都不得不公开说“这是一场软件危机”。

不过,早在20世纪 60 年代中期,计算机科学家就迈出了深入探索并发编程的第一步。在不到 15年的时间里,他们逐步把并发编程思想凝炼成了理论,同时开发出了一套描述方法。之后,他们把这套理论融人编程语言中,并用这些语言来编写操作系统模型。在20 世纪70年代,第一本关于操作系统和并发编程原则的简明参考书问世了。这意味着一个新的编程理论正式形成。探索和发展并发编程思想的最初动机来源于开发可靠的操作系统的强烈欲望。不过,在并发编程理论形成后不久,它就被公认为一个不限于操作系统开发的通用编程理论。

经过多年的进化,并发程序的编写早己没有以前那么复杂了。大多数现代软件设计技术都可以比较方便地产出支持并发的程序。但是,由于并发程序往往具有更复杂的结构,所以编写起来也更困难,且更容易出错。

总体来看,感觉编写并发程序会更加困难的原因有两个:一是缺乏既非常适合开发应用程序又对并发编程有良好支持的语言,二是感觉(也许仅仅是感觉)并发编程的理论大难了。

第一个原因确实客观存在。不过,现在许多语言都在致力于降低编程门槛,实际情况其实己经比之前好很多了。至于第二个原因,我认为这不应该成为专业编程人员躲避编写并发程序的借口,况且在互联网圈子里也避无可避。毫不夸张地讲,如果我们想要真正理解一门编程语言以及领悟怎样才能编好程序,那么学习并发編程这一步必不可少。更不用说,作为软件运行的基础——计算机硬件也在向着并行化快速发展。

管道

管道(pipe)是一种半双工(或者说单向)的通信方式,只能用于父进程与子进程以及同祖先的子进程之间的通信。例如,在使用 shell 命令的时候,常常会用到管道:

ps aux | grep go

shell 为每个命令都创建一个进程,然后把左边命令的标准输出用管道与右边命令的标准输人连接起来。管道的优点在于简单,而缺点则是只能单向通信以及对通信双方关系上的严格限制。

对于管道,Go 是支持的。通过标准库代码包 os/exec 中的 API, 我们可以执行操作系统命令并在此之上建立管道。下面创建一个exec.Cmd 类型的值:

cmd0 := exec.Command("echo","-n","My first command comes from golang.")

对应的 shell 命令:

echo -n "My first command comes from golang."

在exec.Cmd 类型之上有一个名为start 的方法,可以使用它启动命令:

if err := comd0.Start(); err != nil {
    fmt.Printf("Error: The command No.0 can not be startup: %s\n",err)
    return
}

为了创建一个能够获取此命令的输出管道,需要在 if 语句之前加人如下语句:

stdout0, err := cmd0.StdoutPipe()
if err := nil {
    fmt.Printf("Error: Couldn't obtain the stdout pipe for command No.0: %s\n",err)
    return
}

变量cmd0 的stdoutPipe 方法会返回一个输出管道,这里把代表这个输出管道的值赋给了变量 stdout0。 stdout0 的类型是io.Readcloser, 后者是一个扩展了io.Reader 接口的接口类型,并定义了可关闭的数据读取行为。

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...