如何理解和实践Go的并发性?

时间:2017-06-30 14:30:27

标签: go concurrency

我正在学习Go,最强大的功能之一就是并发。我之前编写过PHP脚本,它们逐行执行,这就是为什么我很难理解通道和goroutines。

是否有任何网站或任何其他资源(书籍,文章等),我可以看到可以同时处理的任务,所以我可以与Go一起练习并发?这将是伟大的,如果最后我可以看到解决方案的评论和解释为什么我们这样做,以及为什么这个解决方案比其他解决方案更好。

例如,这里的任务令我困惑,我不知道如何处理:我需要制作有点解析器,接收起点(例如:http://example.com),并开始浏览整个网站(example.com/about,example.com/best-hotels/等),并从每个页面中获取一些文本部分(例如,通过选择器,如h1.titlep.description)然后在所有网站抓取之后,我收到了一段已解析的内容。 我知道如何发出请求,如何使用选择器获取信息,但我不知道如何组织所有goroutines之间的通信。

感谢您提供任何信息和链接。希望这将有助于其他人在将来遇到同样的问题。

1 个答案:

答案 0 :(得分:0)

所以有lots resources online关于并发模式的问题 - 我从快速谷歌搜索获得的那三个。但如果你有一些特定的东西,我想我也可以解决这个问题。

您希望抓取网站并同时从多个网页获取信息,将“信息”存入公共位置(即slice)。这里的方法是使用chan,chaonlinennel,它是一个线程安全的(多个线程可以毫无顾虑地访问它)数据结构,用于从一个线程/ goroutine 引导数据到另一个。

当然,Go中的go关键字是如何生成goroutine。

例如,在func main()主题中:

// get a listOfWebpages
dataChannel := make(chan string)
for _, webpage := range listOfWebpages {
    go fetchDataFromWebpage(webpage, dataChannel)
}

// the dataChannel will be concurrently filled with the data you send to it
for x := range dataChannel {
    fmt.Println(x) // print the header or whatever you scraped from webpage
}

goroutines将是抓取网站并提供dataChannel的功能(你提到你已经知道如何抓取网站)。像这样:

func fetchDataFromWebpage(url string, c chan string) {
    data := scrapeWebsite(url)
    c <- data // send the data to thread safe channel
}

如果您无法理解如何使用并发工具(如通道,互斥锁或WaitGroup),那么您应该首先尝试理解为什么并发可能会出现问题:)我发现最好的例证( to me )是餐饮哲学家问题https://en.wikipedia.org/wiki/Dining_philosophers_problem

  

五位沉默的哲学家坐在圆桌旁,拿着一碗意大利面。叉子放在每对相邻的哲学家之间。

     

每个哲学家都必须交替思考和吃饭。然而,一个哲学家只有在有左右叉的时候才能吃意大利面。每个分支只能由一位哲学家持有,因此只有当另一位哲学家不使用时,哲学家才能使用分叉。在一位个体哲学家吃完之后,他们需要放下两把叉子,这样叉子才能供他人使用。一个哲学家可以在他们的右边或左边的那个上叉,因为它们变得可用,但是在获得两个叉子之前不能开始进食。

如果您正在寻找练习,我建议您实现此问题,以便它失败,然后尝试使用并发模式修复它:) - 还有其他问题,例如有空!创建问题是了解如何解决问题的一步!

如果您在理解如何使用频道时遇到更多麻烦,除了阅读之外,您可以更简单地将频道视为队列,可以从并发线程安全地访问/修改