Go 编程:在通讯中共享内存

未匹配的标注

本文为官方 Go Blog 的中文翻译,详见 翻译说明

Andrew Gerrand
2010 年 7 月 13 日

传统的线程模型 (例如, 通常用 Java、 C++ 以及 Python 编写程序时) 要求程序员使用共享内存在线程之间进行通信。 通常情况下, 共享数据结构受到锁的保护, 线程将争夺这些锁来访问数据。 在某些情况下, 通过使用线程安全的数据结构 (例如 Python 的 Queue) 可以使操作变得更容易。

Go 的并发原语 —— 协程和信道 —— 提供了一种独特而不失优雅的方式来构造并发软件。 (这些概念有一个 有趣的历史 以 C. A. R. Hoare 的 通信顺序过程 开头。) Go 明确使用锁来调节对共享数据的访问, 因此鼓励使用信道在协程之间传递对数据的引用。 这种方式可确保在给定时间只有一个协程可以访问数据。 该概念可以在文档 高效的 Go 编程 里看到总结 (值得所有 Go 程序员一读):

不要通过共享内存来通信; 而应通过通信来共享内存.

考虑一个轮询 URLs 列表的程序。 在传统的线程环境中, 人们可能会像这样构造其数据:

type Resource struct {
    url        string
    polling    bool
    lastPolled int64
}

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

然后, 一个 Poller 函数 (其中的许多函数会在单独的线程中运行) 看起来如下:

func Poller(res *Resources) {
    for {
        // 获取最近轮询最少的资源
        // 并将其标记为已轮询
        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
        }

        // 查询 URL

        // 更新资源的轮询和最后轮询的时间
        res.lock.Lock()
        r.polling = false
        r.lastPolled = time.Nanoseconds()
        res.lock.Unlock()
    }
}

这个函数大概需要写满一页, 并且需要更多详细的代码才能完成想要的功能。 甚至还不包括 URL 轮询逻辑 (虽然只有几行), 更不会优雅地处理资源池的耗尽。

让我们看下使用 Go 套路实现的相同功能。 在此示例中, 轮询器是一个函数, 该函数从输入通道接收要轮询的资源, 并在完成后将其发送到输出通道。

type Resource string

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

        // 将处理后的资源发送出去
        out <- r
    }
}

在上一个示例中需要费尽心思的逻辑在这个示例显然不存在, 并且我们的资源数据结构也不需要包含记录数据。 实际上, 剩下的就是重要的部分。 这应该对你了解这门简单语言的函数功能有所帮助。

上面的代码片段还有不少遗漏之处。 这里有一些使用 Go 套路完成想法的程序, 请参阅 通过通信来共享内存.

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/go-blog/share-m...

译文地址:https://learnku.com/docs/go-blog/share-m...

上一篇 下一篇
Summer
贡献者:3
讨论数量: 0
发起讨论 只看当前版本


暂无话题~