在通道上进行非阻塞多次接收

似乎到处都在讨论从通道读取应该始终是阻塞操作。态度似乎是这就是Go的方式。这有一定道理,但我正在尝试弄清楚如何从渠道汇总内容。

比如发送http请求。假设我有一个生成数据流的管道设置,所以我有一个生成队列/点流的通道。然后我可以让一个 goroutine 监听这个通道并发送一个 HTTP 请求来将它存储在一个服务中。这有效,但我正在为每个点创建一个 http 请求。

我发送的端点也允许我批量发送多个数据点。我想做的是

  1. 读取尽可能多的值,直到我阻塞通道。

  2. 组合它们/发送单个 http 请求。

  3. 然后在频道上阻塞,直到我可以再次阅读。

这就是我在 C 中使用线程安全队列和 select 语句完成任务的方式。在可能的情况下基本上刷新整个/队列缓冲区。这是一种有效的技术吗?

似乎 go select 语句确实给了我类似于 C 的选择的东西,但我仍然不确定通道上是否有“非阻塞读取”。

编辑:我也愿意接受我想要的可能不是 Go Way,但不断粉碎不间断的 http 请求对我来说似乎也是错误的,尤其是如果它们可以聚合的话。如果有人有一个很酷的替代架构,但我想避免诸如神奇地缓冲 N 个项目或等待 X 秒直到发送之类的事情。


人到中年有点甜
浏览 185回答 2
2回答

烙印99

Dewy Broto 为您的问题提供了很好的解决方案。这是一个简单直接的解决方案,但我想更广泛地评论您如何为不同的问题寻找解决方案。Go 使用通信顺序进程代数 (CSP) 作为通道、选择和轻量级进程 ('goroutines') 的基础。CSP保证事件的顺序;当您通过做出选择(又名select)这样做时,它只会引入非确定性。有保证的排序有时被称为“先发生”——它使编码比替代(广受欢迎)的非阻塞风格简单得多。它还为创建组件提供了更多空间:通过渠道以可预测的方式与外部世界交互的长期功能单元。或许关于频道阻塞的讨论在人们学习围棋的方式上设置了心理障碍。我们在 I/O 上阻塞,但我们在通道上等待。如果系统作为一个整体有足够的并行松弛度(即其他活动的 goroutines)来保持 CPU 忙碌,那么等待通道是不会皱眉的。可视化组件所以,回到你的问题。让我们从组件的角度考虑它,您有许多需要探索的点来源。假设每个源都是一个 goroutine,然后它在您的设计中形成一个带有输出通道的组件。Go 允许共享通道端,因此许多源可以安全地按顺序将它们的点交错到单个通道上。您无需执行任何操作 - 这就是频道的工作方式。Dewy Broto 描述的批处理功能本质上是另一个组件。作为一种学习练习,以这种方式表达它是一件好事。批处理组件具有一个点输入通道和一个批次输出通道。最后,HTTP i/o 行为也可以是一个具有一个输入通道而没有输出通道的组件,仅用于接收整批点然后通过 HTTP 发送它们。以只有一个来源的简单情况为例,这可能是这样描述的:+--------+     point     +---------+     batch     +-------------+| source +------->-------+ batcher +------->-------+ http output |+--------+               +---------+               +-------------+这里的目的是在基本层面描述不同的活动。这有点像数字电路图,这不是巧合。你确实可以在 Go 中实现它,它会起作用。它甚至可能工作得很好,但在实践中您可能更喜欢通过组合成对的组件来优化它,必要时重复。在这种情况下,很容易将批处理器和 http 输出结合起来,这样做最终会得到 Dewy Broto 的解决方案。重要的一点是 Go 并发最容易发生(a)不要预先担心阻塞;(b)描述需要在相当细粒度的级别上发生的活动(在简单的情况下,您可以在头脑中完成);(c)如有必要,通过将功能组合在一起进行优化。我将把更高级的可视化移动通道端(Pi-Calculus)主题作为挑战,其中通道用于将通道端发送到其他 goroutine。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go