因此,除了处理多个服务器请求之外,是否还有其他时间并发相关?我问,因为它是如此内置,如果我不使用它我会感到浪费,但我几乎找不到用它。
答案 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使用并发性的一个很好的例子,因为它是一种表达问题解决方案的简单方法:
对此进行概括,任何生产者 - 消费者问题都非常适合使用通道将生产者的输出传递给消费者的2个goroutine。
并发的另一个好用途是与多个输入/输出源(磁盘,网络,终端等)进行交互。只要结果来自任何这些来源,您的程序就应该能够醒来并做一些工作。可以使用一个线程和诸如poll(2)或select(2)之类的系统调用来执行此操作。当你的线程醒来时,它必须弄清楚结果是什么,在相关任务中找到它停止的位置,然后从那里拿起。这是你需要写的很多代码。
使用每个任务一个goroutine编写代码要容易得多。然后在goroutine中隐式捕获该任务的状态,并从中断的地方拾取就像醒来并运行一样简单。
答案 2 :(得分:3)
我的2美分......如果你只考虑并发环境中的频道/ goroutines,你就错过了这条船。
虽然go不是对象语言或严格来说是函数式语言,但它允许您从两者中获取设计特征并应用它们。
面向对象设计的基本原则之一是单一责任 的原理即可。应用此原则迫使您根据消息而不是复杂的对象行为来考虑设计。可以在go中使用这些相同的设计约束,以允许您开始考虑连接单一用途函数的“通道上的消息”。
这只是一个例子,但如果你开始这样思考,你会看到更多。
答案 3 :(得分:0)
也不是Go的专家,所以我的一些方法可能是非规范的,但是到目前为止我发现了一些有用的并发方法:
并发可能(读取:“有时,但不一定总是”)当您的操作可以彼此独立运行但是否则会按顺序运行时非常有用。即使这些操作依赖于某些点上的数据或来自其他goroutine的某种信号,您也可以通过频道进行通信。
对于这些问题的一些灵感和重要区别,以及一些有趣的gopher图片,请参阅Concurrency is not Parallelism。