为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
人到中年有点甜 2021-08-23 15:25:48
似乎到处都在讨论从通道读取应该始终是阻塞操作。态度似乎是这就是Go的方式。这有一定道理,但我正在尝试弄清楚如何从渠道汇总内容。比如发送http请求。假设我有一个生成数据流的管道设置,所以我有一个生成队列/点流的通道。然后我可以让一个 goroutine 监听这个通道并发送一个 HTTP 请求来将它存储在一个服务中。这有效,但我正在为每个点创建一个 http 请求。我发送的端点也允许我批量发送多个数据点。我想做的是读取尽可能多的值,直到我阻塞通道。组合它们/发送单个 http 请求。然后在频道上阻塞,直到我可以再次阅读。这就是我在 C 中使用线程安全队列和 select 语句完成任务的方式。在可能的情况下基本上刷新整个/队列缓冲区。这是一种有效的技术吗?似乎 go select 语句确实给了我类似于 C 的选择的东西,但我仍然不确定通道上是否有“非阻塞读取”。编辑:我也愿意接受我想要的可能不是 Go Way,但不断粉碎不间断的 http 请求对我来说似乎也是错误的,尤其是如果它们可以聚合的话。如果有人有一个很酷的替代架构,但我想避免诸如神奇地缓冲 N 个项目或等待 X 秒直到发送之类的事情。
查看完整描述

2 回答

?
烙印99

TA贡献1829条经验 获得超13个赞

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。


查看完整回答
反对 回复 2021-08-23
  • 2 回答
  • 0 关注
  • 177 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信