我用golang错误地使用频道吗?

时间:2017-01-20 00:35:20

标签: go channel

我来自Node.js背景,它非常容易做一些异步工作,然后在完成这个长时间运行的任务时做更多的工作,我确信它在Go中是相同的但是我还没有完全了解渠道如何运作。

我为我玩的旧游戏构建解析器,该游戏分析来自拍卖数据日志的行并解析它们以通过套接字io流式传输到网站上的实时订阅源。一个文件一次可以发送100行,我的解析器必须一次分析每一行,并从每一行中提取元信息(例如项目,项目价格等)。

每一行都有针对它的for循环运行(这假定了一个项目列表来自正则表达式的部分):

itemChannel := make(chan Item)

for _, itemName := range itemList {
    item := Item {
        Name: itemName,
    }

    // Long running method which does parsing for the item such as pricing, quantity and makes some http calls (runs 75ms on average)
    go item.FetchData(itemChannel)

    // Read from the channel when its done
    raw := <-itemChannel
    auction.Items = append(auction.Items, raw)
    auction.Seller = seller
}

auctions = append(auctions, auction)
fmt.Println("Appended auction: ", auction)
go c.publishToRelayService(auction)

现在(从观察中)似乎raw := <-itemChannel导致循环阻塞,直到goroutine完成并将其数据传回(这肯定意味着以item.FetchData(itemChannel)运行会做同样的事情。我可以从数据中读取数据,但是尽可能快地突破循环迭代。有些行有15-20个项目导致程序在解析下一行之前停止约2-3秒我希望能够尽快突破并处理下一行,以尽可能快地保持解析器。是否有类似于Node中的Promises的机制,我可以将完成处理程序链接到每个完成item.FetchData()

注意 fetchChannel会在所有提取工作完成后写入我的项目类型内部。

2 个答案:

答案 0 :(得分:2)

您可以编写一个不同的go例程,等待通道中的新数据并对其进行处理。 这种方式生产者和消费者并行运行,当生产者完成生产消费者必须这样做,消费者是一个轻过程

您可以使用done频道来表明消费者已完成

以下是更改代码的方法

itemChannel := make(chan Item)
done := make(chan bool)
//Consumer
go func(channel chan Item) {
    for raw := range channel {
        auction.Items = append(auction.Items, raw)
        auction.Seller = seller
        auctions = append(auctions, auction)
    }
    done <- true
}(itemChannel)

//Producer
for _, itemName := range itemList {
    item := Item{
        Name: itemName,
    }

    // Long running method which does parsing for the item such as pricing, quantity and makes some http calls (runs 75ms on average)
    go item.FetchData(itemChannel)

}

<-done
fmt.Println("Appended auction: ", auction)
go c.publishToRelayService(auction)

答案 1 :(得分:1)

就更广泛的问题而言,从Node.js转移到Go / CSP频道,你需要先考虑回调。我使用的每个反应/异步范例都是某种形式的回调装置,易于使用。但是CSP不会尝试这样。

Go中的关键不同之处在于,轻量级goroutine的协同调度大致独立于操作系统线程(尽管实现者通常努力通过操作系统线程技巧尽可能地利用CPU核心)在引擎盖下)。与动作回调没有真正的比较。

每个goroutines都有自己独立的生命周期。它可能很短。或者,如果goroutine包含一些循环,它可能存在一段时间并且看起来像一个actor(在actor模型中)。

这是您探索通信顺序进程(CSP)所需的思路。对数字电子构建模块中的goroutines的思考也可以是有用的类比。门和线与goroutines和channel类似。

此外,触发器可以从几个门构建 - 以同样的方式,goroutines可以由内部通道连接的“较小”goroutine组成。如果你做对了,“更大”的goroutine上的外部频道是其合作者唯一关注的问题(内部频道被隐藏)。

这开辟了设计软件的新方法,也是Rob Pike所倡导的事情之一:Concurrency is not Parallelism。不同的想法。

一个例子可能是模拟软件(康威的生命游戏规模更大)。基于对所涉及的每个细胞的个体行为进行建模,我看到了血管中血液流动和凝固的非常引人注目的模拟。该演示有4000万个并发实体,这种方法非常令人印象深刻,可以在普通的笔记本电脑上运行。