Share-Memory-by-Communicating

Origin: https://blog.golang.org/share-memory-by-communicating

传统的多线程编程(比如Java,C++,Python等)需要码农通过在线程间共享内存的方式通信。一般来讲,共享的数据结构用锁来保护,线程想获取数据的时候必须先拿到锁。在某些情况下,用线程安全的数据结构能使其变得更加容易,比如Python的Queue。

Go的并发原语 - goroutine和channel - 提供了另一种优雅的方式去写并发软件。(这些概念有一个有趣的历史,起源于C. A. R. Hoare的 Communicating Sequential Processes)Go鼓励用channel的方式在goroutine之间传递引用数据,而不是声明一把锁去协调对共享数据的访问。这样的操作保证了在同一时刻只有一个goroutine拥有对数据的访问权。这个概念在高效Go编程(go程序员的必读文档)中有总结。

不要通过共享的方式去沟通,通过沟通的方式共享内存。

考虑这样一个程序,它轮旬一堆的URL。在传统的多线程编程中,你或许用以下的数据结构:

type Resource struct {
    url        string
    polling    bool
    lastPolled int64
}

type Resources struct {
    data []*Resource
    lock *sync.Mutex
}

然后有一个Poller的函数(并发执行)看起来可能会这样:

func Poller(res *Resources) {
    for {
        // get the least recently-polled Resource
        // and mark it as being polled
        res.lock.Lock()
        var r *Resource
        for _, v := range res.data {
            if v.polling {
                continue
            }
            if r == nil || v.lastPolled < r.lastPolled {
                r = v
            }
        }
        if r != nil {
            r.polling = true
        }
        res.lock.Unlock()
        if r == nil {
            continue
        }

        // poll the URL

        // update the Resource's polling and lastPolled
        res.lock.Lock()
        r.polling = false
        r.lastPolled = time.Nanoseconds()
        res.lock.Unlock()
    }
}

这个函数看起来比较长,并且还会更长(需要更多的细节去完善)。它甚至不包含对于获取URL的逻辑,以及对于辛苦获取到的资源的优雅处理。

然后我们再来对比一下用go的方式。在这个例子中,Poller函数的功能是从输入的channel中接收要被获取的URL地址,处理完成后再传递给输出channel:

type Resource string

func Poller(in, out chan *Resource) {
    for r := range in {
        // poll the URL

        // send the processed Resource to out
        out <- r
    }
}

这种优雅的实现,对于开头的例子而言显然是没有的,而且我们的Resource在结构上也没有了需要记录的数据。事实上,剩下都是必须的代码。这些强大而简单的语言特性应该能够给你一些暗示了。

在上面的代码片段中有很多遗漏,更详细的代码参见此处

By Andrew Gerrand


关于用锁还是用channel,附上一篇go自己的说明: https://github.com/golang/go/wiki/MutexOrChannel

也参见唐生的回答 - 知乎

另外个人的看法是,哪个适合就用哪个,没有好坏之分,只有在当前情境下合不合适。

comments powered by Disqus