使用Go进行编程的一些模型

对于编程语言,在最初的时候,我觉得每种语言都是不一样的,不同语言需要一个一个去学习。最开始学的是C++,后来当我学完了JAVA之后,再学C,再学Python,渐渐的,我觉得各种语言都是类似的。只要对着语言说明,看上一上午,就能写了。而现在,我发现语言分不用的类别,同一类语言的语法和用法相似,而不同类的语言却有各自不同的特质和灵魂。

使用Go语言编程已经将近一年时间了,开始只是觉得用的挺舒服,而且有着很高的性能。但是随着程序的复杂性的增加,对于比较大的逻辑,尤其是管理多个协程之间的协作,成为了一个瓶颈。总感觉有一种潜在的针对Go语言的并发编程模型。首先,实现第三方包的时候,最好不要在内部启用协程。而是暴露借口或者函数给使用者。因为包内部启动协程,对于调用者而言是不可控的。一旦,协程内部运行出现致命错误,包的调用者的程序也就崩溃了。这样对于控制程序非常不利。因此应该显式的提供调用方法给包的使用者,由包的使用者去控制程序运行。

在实际使用中往往会有这样的模型,一个数据或者请求过来,然后启用一个协程,去处理。Go内置的Http包,就是这样一个模型,当一个请求过来之后,启动一个协程处理请求。但是很多时候,主的控制者需要控制并且获取子任务的运行状态,这样才能保证不会出现协程泄漏的情况。这个时候就需要使用channel来作为协程之间通信的通道。而这个channel应该如何来组织呢?这是一个问题,这里我提出一个规则:channel谁创建谁关闭。在对channel操作中,当channel关闭的时候,对channel的读取者是可以感知到的,例如:

select {
    case value, ok := <-channel1:
        if !ok{
            这时channel已经关闭了
        }
}

for value := range channel1{
    当channel关闭的时候,循环自动就会结束了。
}

但是当channel已经关闭,但是channel在未知的情况下,对channel执行写入操作的话则会造成panic。这样会导致整个程序崩溃。如果由创建者来关闭channel的话,就可以知道哪些下游程序会对channel进行写入操作,因此就可以先停止所有对channel的写入,然后再关闭channel。这样,同时又可以控制对channel进行写入操作的协程。

在使用多协程进行编程的时候,有些情况下只需要使用关键词go创建一个协程,然后就不管了,随它执行完以后,自然死亡。但是更多时候,我们需要对自己启动的协程负责。毕竟总是始乱终弃会出事的。看到golang官方博客写了一篇文章,讲解了并发编程模型。在创建一个协程的时候,会传入一个由外部创建的channel,用于控制协程的执行。这个channel对于被创建的协程而言,它只会从channel读取数据,然后执行操作,也就是说它只会接受外界命令,但是外界并不知道它目前处于什么样的一个状态。因此,必要的话我们需要传入另一个channel,或者另一个可调用的接口,使得外界可以感知到被创建协程的心跳。这样子,整个模型就变得像一个典型的Master,Slave模型。至于如何协调好这一整个模型的运行,就要靠自己的本事了。

站在Go语言的大门前,我只是觉得里面充满无限想法。继续研究!

Xiang Chao 30 March 2014
blog comments powered by Disqus
Fork me on GitHub