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

Select 在通道上进行非阻塞多接收,select,go,nonblocking,Select,Go,Nonblocking,似乎到处都在讨论从通道读取数据应该始终是一个阻塞操作。人们的态度似乎是这样的。这是有道理的,但我正试图弄清楚如何从渠道中聚合内容 例如,发送http请求。假设我有一个生成数据流的管道设置,所以我有一个生成队列/点流的通道。然后我可以让一个goroutine监听这个频道,并发送一个HTTP请求将其存储在服务中。这是可行的,但我正在为每个点创建一个http请求 我正在发送的端点也允许我批量发送多个数据点。我想做的是 读取尽可能多的值,直到我在通道上阻塞为止 合并它们/发送单个http请求 然后封锁频

似乎到处都在讨论从通道读取数据应该始终是一个阻塞操作。人们的态度似乎是这样的。这是有道理的,但我正试图弄清楚如何从渠道中聚合内容

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

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

  • 读取尽可能多的值,直到我在通道上阻塞为止
  • 合并它们/发送单个http请求
  • 然后封锁频道,直到我能阅读为止 再一次
  • 这就是我在C中使用threadsafe队列和select语句所做的事情。如果可能,基本上刷新整个/队列缓冲区。这是围棋中的有效技术吗

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


    编辑:我也愿意接受我的意图,但不断粉碎不停的http请求对我来说也是错误的,特别是如果它们可以聚合的话。如果有人有一个很酷的替代体系结构,但我想避免像神奇地缓冲N个项目,或等待X秒直到发送这样的事情。

    以下是如何批处理直到通道为空。变量
    batch
    是数据点类型的一部分。变量
    ch
    是数据点类型的通道

    var batch []someType
    for {
        select {
        case v := <-ch:
           batch = append(batch, v)
        default:
           if len(batch) > 0 {
               sendBatch(batch)
               batch := batch[:0]
           }
           batch = append(batch, <-ch)  // receiving a value here prevents busy waiting.
        }
    }
    
    var批处理[]someType
    为了{
    挑选{
    案例五:=0{
    发送批(批)
    批次:=批次[:0]
    }
    
    batch=append(批处理,以下是如何批处理直到通道为空。变量
    batch
    是数据点类型的一部分。变量
    ch
    是数据点类型的通道

    var batch []someType
    for {
        select {
        case v := <-ch:
           batch = append(batch, v)
        default:
           if len(batch) > 0 {
               sendBatch(batch)
               batch := batch[:0]
           }
           batch = append(batch, <-ch)  // receiving a value here prevents busy waiting.
        }
    }
    
    var批处理[]someType
    为了{
    挑选{
    案例五:=0{
    发送批(批)
    批次:=批次[:0]
    }
    
    batch=append(batch,Dewy Broto为您的问题提供了一个很好的解决方案。这是一个直截了当的解决方案,但我想更广泛地评论一下您可能如何为不同的问题找到解决方案

    Go使用通信顺序过程代数(CSP)作为通道、选择和轻量级过程(“goroutines”)的基础。CSP保证事件的顺序;它只在您做出选择时引入非确定性(也称为
    select
    )-它使编码比另一种(广泛流行的)非阻塞样式简单得多。它还为创建组件提供了更大的空间:具有长寿命功能的单元,通过可预测的方式与外部世界进行交互

    也许说阻塞通道会给人们学习围棋带来心理障碍。我们阻塞I/O,但我们等待通道。如果系统作为一个整体有足够的并行松弛度(即其他活动的goroutine)来保持CPU繁忙,那么等待通道是不应该被反对的

    可视化组件

    那么,回到您的问题上来。让我们从组件的角度来考虑它。,您有许多需要探索的点源。假设每个源是一个goroutine,它在您的设计中形成一个带有输出通道的组件。Go让通道端共享,因此许多源可以按顺序安全地交错它们的点o单一频道。你不必做任何事情-这只是频道的工作方式

    Dewy Broto描述的批处理函数本质上是另一个组件。作为学习练习,用这种方式表达它是一件好事。批处理组件有一个点输入通道和一个批处理输出通道

    最后,HTTP i/o行为也可以是一个只有一个输入通道而没有输出通道的组件,只用于接收整批点,然后通过HTTP发送它们

    仅以一个源为例,可以这样描述:

    +--------+     point     +---------+     batch     +-------------+
    | source +------->-------+ batcher +------->-------+ http output |
    +--------+               +---------+               +-------------+
    
    这里的目的是描述不同的基本活动,有点像数字电路图,这不是巧合

    您确实可以在Go中实现这一点,而且它会起作用。它甚至可能工作得很好,但实际上您可能更喜欢通过组合成对的组件来优化它,在必要时反复进行。在这种情况下,很容易将批处理程序和http输出结合起来,这样做最终会得到Dewy Broto的解决方案

    重要的一点是,Go并发最容易通过

    • (a) 不要预先担心阻塞
    • (b) 描述需要在相当细粒度的级别上进行的活动(在简单的情况下,您可以在头脑中进行)
    • (c) 如有必要,通过将功能组合在一起进行优化

    作为一项挑战,我将留下一个更高级的主题,即可视化移动频道终端(Pi演算)使用通道将通道端发送到其他goroutine的位置。

    杜威·布罗托为您的问题提供了一个很好的解决方案。这是一个简单直接的解决方案,但我想更广泛地评论一下您如何为不同的问题找到解决方案

    Go使用通信顺序过程代数(CSP)作为通道、选择和轻量级过程(“goroutines”)的基础。CSP保证事件的顺序;它只在您做出选择时引入非确定性(也称为
    select
    )-它使编码变得更加简单