go - 如何在循环中使用 gorutines 来填充结构?
问题描述
有这样的模型:
type ChromeBasedDirections struct {
CurrencyFromName string
CurrencyToName string
URL string
ParseResponse ParseResponse
}
type ParseResponse struct {
CurrentPrice float64
Change24H float64
Err error
}
type ParseResponseChan struct {
URL string
CurrentPrice float64
Change24H float64
Err error
}
函数是这样的:
func ParseBNCByURL(u string, chanResponse chan models.ParseResponseChan) {
var parseResponse models.ParseResponseChan
//..
// code that fill up parseResponse
//..
if err != nil {
parseResponse.Err = err
chanResponse <- parseResponse
return
}
parseResponse.CurrentPrice = price
parseResponse.Change24H = change24H
chanResponse <- parseResponse
return
}
这就是函数调用的方式:
func initParserMultiTread() {
var urls = []string{"url_0","url_1","url_2","url_n"} // on production it will be taken from the json file
var chromeBasedDirections []models.ChromeBasedDirections
for _, url := range urls {
chromeBasedDirections = append(chromeBasedDirections, models.ChromeBasedDirections{
CurrencyFromName: "",
CurrencyToName: "",
URL: url,
ParseResponse: models.ParseResponse{},
})
}
var parseResponseChan = make(chan models.ParseResponseChan) // here's how to do without hardcode?
for _, dir := range chromeBasedDirections {
go controllers.ParseBNCByURL(dir.URL, parseResponseChan)
}
}
如果initParserMultiTread
被执行,函数将在ParseBNCByURL
执行之前完成。这是因为通道尚未被读取。如果可以使用硬编码,那么每个 url_n 都可以创建自己的 chan models.ParseResponseChan
,然后在循环中比较ChromeBasedDirections.URL
and ParseResponseChan.URL
,如果匹配则填写ChromeBasedDirections.ParseResponse
.
但我需要避免硬编码并循环执行所有操作。一般来说,这远不是第一个选项,因为我尝试对ParseBNCByURL
函数进行多线程执行。
也就是有一个ChromeBasedDirections
填充了CurrencyFrom/ToName
和URL
字段的模型,我需要ParseBNCByURL
在多线程中执行,会填充ParseResponse
.
我又试了一次,但该功能在多线程模式下不起作用:
var urls = []string{"url_0","url_1","url_2","url_n"}
var chromeResults []models.ChromeBasedDirections
for _, url := range urls {
var chromeResult = make(chan models.ChromeBasedDirections)
go controllers.ParseBNCByURL(url, chromeResult)
chromeResults = append(chromeResults, <-chromeResult)
}
解决方案
您的代码的问题是您没有在parseResponseChan
任何地方阅读。你所有的 goroutines 都会因此被阻塞,这就是initParserMultiTread
函数在你的 goroutines 之前完成的原因。
您需要添加用于读取parseResponseChan
通道的代码,以及用于在parseResponseChan
所有 goroutine 执行完成后关闭通道的代码。
一种解决方案是与sync.WaitGroup
.
首先改变你的ParseBNCByURL
功能。这个函数需要在完成时发送一个信号。
func ParseBNCByURL( wg *sync.WaitGroup, u string, chanResponse chan models.ParseResponseChan) {
defer wg.Done() //this signals when the goroutine is done
//the rest of the function's body
在initParserMultiTread
函数中,您需要一种方法来等待来自所有 goroutine 的信号以关闭parseResponseChan
通道并从该通道读取响应。
func initParserMultiTread() {
var urls = []string{"url_0","url_1","url_2","url_n"} // on production it will be taken from the json file
var chromeBasedDirections []models.ChromeBasedDirections
var wg sync.WaitGroup
wg.Add(len(urls)) // add how many goroutines will be initialized
for _, url := range urls {
chromeBasedDirections = append(chromeBasedDirections, models.ChromeBasedDirections{
CurrencyFromName: "",
CurrencyToName: "",
URL: url,
ParseResponse: models.ParseResponse{},
})
}
var parseResponseChan = make(chan models.ParseResponseChan)
//init a goroutine for closing the parseResponseChan once all goroutines are done
go func(wg *sync.WaitGroup, ch chan models.ParseResponseChan) {
wg.Wait() //wait for all goroutines to send the signal
close(ch) //close the channel
}(&wg, parseResponseChan)
for _, dir := range chromeBasedDirections {
go controllers.ParseBNCByURL(&wg, dir.URL, parseResponseChan)
}
//read the responses from the channel
for response := range parseResponseChan {
//some code to handle the responses
}
}
一旦所有的 goroutine 都被初始化,你就开始从parseResponseChan
通道中读取。这将阻止initParserMultiTread
函数返回,直到所有 goroutine 都执行完毕并且parseResponseChan
通道关闭。
推荐阅读
- apache-spark - 前向填充多列可重用功能代码
- c++ - 在 C++ 中使用 AssocQueryString 获取可执行路径
- c - 将相同的元素从 2 个升序排序的链表复制到一个新链表
- python - 如何让我保存的 mp4 与 plot.show() 的输出完全匹配?
- javascript - UI中的Wordpress插件访问方法
- git - Jenkinsfile 和 env.GIT_BRANCH
- c# - 无法将 System.Linq.IOrderedQuerable 转换为 System.Collection.Generic.List 错误
- ios - Obj-c - 如果没有搜索结果,返回表格视图中的 1 个单元格?
- r - 如何使 R 的 philentropy::distance 函数完全安静?
- sql-server - 无法从 Visual Studio 执行 .sql 文件