什么时候我应该在golang中使用并发?

时间:2013-11-02 23:09:43

标签: concurrency go

因此,除了处理多个服务器请求之外,是否还有其他时间并发相关?我问,因为它是如此内置,如果我不使用它我会感到浪费,但我几乎找不到用它。

4 个答案:

答案 0 :(得分:7)

不是Go中的专家(还),但我会说:

每当最容易这样做时。

Go中并发模型的优点在于,它并不是一个多核架构,它通常会破坏事物的检查和平衡 - 它是一个多线程范例,不仅适用于多线程 - 核心架构,它也非常适合分布式系统架构。

您不必为多个goroutines做出特殊安排,以便和谐地协同工作 - 他们就是这么做!

这是一个自然并发算法的例子 - 我想将多个通道合并为一个。一旦所有输入通道都耗尽,我想关闭输出通道。

使用并发更简单 - 事实上它甚至看起来不像并发 - 它看起来几乎是程序性的。

/*
  Multiplex a number of channels into one.
*/
func Mux(channels []chan big.Int) chan big.Int {
    // Count down as each channel closes. When hits zero - close ch.
    var wg sync.WaitGroup
    wg.Add(len(channels))
    // The channel to output to.
    ch := make(chan big.Int, len(channels))

    // Make one go per channel.
    for _, c := range channels {
        go func(c <-chan big.Int) {
            // Pump it.
            for x := range c {
                ch <- x
            }
            // It closed.
            wg.Done()
        }(c)
    }
    // Close the channel when the pumping is finished.
    go func() {
        // Wait for everyone to be done.
        wg.Wait()
        // Close.
        close(ch)
    }()
    return ch
}

我必须在这里做出并发的唯一让步是使用sync.WaitGroup作为并发计数的计数器。

请注意,这不仅仅是我自己的工作 - 我对此here有很多帮助。

答案 1 :(得分:5)

以下是Go的发明人之一Rob Pike使用并发性的一个很好的例子,因为它是一种表达问题解决方案的简单方法:

Lexical Scanning in Go

对此进行概括,任何生产者 - 消费者问题都非常适合使用通道将生产者的输出传递给消费者的2个goroutine。

并发的另一个好用途是与多个输入/输出源(磁盘,网络,终端等)进行交互。只要结果来自任何这些来源,您的程序就应该能够醒来并做一些工作。可以使用一个线程和诸如poll(2)或select(2)之类的系统调用来执行此操作。当你的线程醒来时,它必须弄清楚结果是什么,在相关任务中找到它停止的位置,然后从那里拿起。这是你需要写的很多代码。

使用每个任务一个goroutine编写代码要容易得多。然后在goroutine中隐式捕获该任务的状态,并从中断的地方拾取就像醒来并运行一样简单。

答案 2 :(得分:3)

我的2美分......如果你只考虑并发环境中的频道/ goroutines,你就错过了这条船。

虽然go不是对象语言或严格来说是函数式语言,但它允许您从两者中获取设计特征并应用它们。

面向对象设计的基本原则之一是单一责任原理即可。应用此原则迫使您根据消息而不是复杂的对象行为来考虑设计。可以在go中使用这些相同的设计约束,以允许您开始考虑连接单一用途函数的“通道上的消息”。

这只是一个例子,但如果你开始这样思考,你会看到更多。

答案 3 :(得分:0)

也不是Go的专家,所以我的一些方法可能是非规范的,但是到目前为止我发现了一些有用的并发方法:

  • 在等待网络请求,磁盘I / O或数据库查询完成时执行操作
  • 更快地执行分而治之算法
  • 由于goroutines是函数,函数是Go中的一等公民,因此可以将它们作为变量传递。当您的程序有许多自主部件时,这很方便。 (例如,我正在模拟城市的交通系统。每辆车都是自己的goroutine,他们通过使用渠道与交叉路口和其他车辆进行通信。每个车辆都有自己的东西。)
  • 跨不同设备的同时I / O操作
  • 使用并发在图像中的一组点上执行Dijkstra算法以绘制“智能剪刀”线 - 每点一个goroutine使得此实现明显更快。
  • GoConvey使用并发性同时跨包运行测试,以便在使用the web UI进行调试时更快地响应更改。 (作为一个固有的奖励,这为测试序列增加了一些伪随机性,因此您的测试结果是真正一致的。)

并发可能(读取:“有时,但不一定总是”)当您的操作可以彼此独立运行但是否则会按顺序运行时非常有用。即使这些操作依赖于某些点上的数据或来自其他goroutine的某种信号,您也可以通过频道进行通信。

对于这些问题的一些灵感和重要区别,以及一些有趣的gopher图片,请参阅Concurrency is not Parallelism