我正在学习Go,最强大的功能之一就是并发。我之前编写过PHP脚本,它们逐行执行,这就是为什么我很难理解通道和goroutines。
是否有任何网站或任何其他资源(书籍,文章等),我可以看到可以同时处理的任务,所以我可以与Go一起练习并发?这将是伟大的,如果最后我可以看到解决方案的评论和解释为什么我们这样做,以及为什么这个解决方案比其他解决方案更好。
例如,这里的任务令我困惑,我不知道如何处理:我需要制作有点解析器,接收起点(例如:http://example.com),并开始浏览整个网站(example.com/about,example.com/best-hotels/等),并从每个页面中获取一些文本部分(例如,通过选择器,如h1.title
和p.description
)然后在所有网站抓取之后,我收到了一段已解析的内容。
我知道如何发出请求,如何使用选择器获取信息,但我不知道如何组织所有goroutines之间的通信。
感谢您提供任何信息和链接。希望这将有助于其他人在将来遇到同样的问题。
答案 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
五位沉默的哲学家坐在圆桌旁,拿着一碗意大利面。叉子放在每对相邻的哲学家之间。
每个哲学家都必须交替思考和吃饭。然而,一个哲学家只有在有左右叉的时候才能吃意大利面。每个分支只能由一位哲学家持有,因此只有当另一位哲学家不使用时,哲学家才能使用分叉。在一位个体哲学家吃完之后,他们需要放下两把叉子,这样叉子才能供他人使用。一个哲学家可以在他们的右边或左边的那个上叉,因为它们变得可用,但是在获得两个叉子之前不能开始进食。
如果您正在寻找练习,我建议您实现此问题,以便它失败,然后尝试使用并发模式修复它:) - 还有其他问题,例如有空!创建问题是了解如何解决问题的一步!
如果您在理解如何使用频道时遇到更多麻烦,除了阅读之外,您可以更简单地将频道视为队列,可以从并发线程安全地访问/修改