# In the following snippet (producer-receiver using channel), would it be possible to iterate the channel instead of using "loop" followed by "if" (perhaps with a macro)?

**URL:** <https://forum.crystal-lang.org/t/in-the-following-snippet-producer-receiver-using-channel-would-it-be-possible-to-iterate-the-channel-instead-of-using-loop-followed-by-if-perhaps-with-a-macro/4097>\
**Category:** Help & Support\
**Created:** [November 27, 2021, 8:31pm UTC](https://forum.crystal-lang.org/t/in-the-following-snippet-producer-receiver-using-channel-would-it-be-possible-to-iterate-the-channel-instead-of-using-loop-followed-by-if-perhaps-with-a-macro/4097 "2021-11-27T20:31:50Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![serge-hulne](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/serge-hulne/32/1211_2.png) [@serge-hulne](https://forum.crystal-lang.org/u/serge-hulne)\
**Post date:** [November 27, 2021, 8:31pm UTC](https://forum.crystal-lang.org/t/in-the-following-snippet-producer-receiver-using-channel-would-it-be-possible-to-iterate-the-channel-instead-of-using-loop-followed-by-if-perhaps-with-a-macro/4097/1 "2021-11-27T20:31:50Z")

</div>

```auto
c1 = Channel(Int32).new
c2 = Channel(Nil).new

spawn do
  (1..10).each do |i|
    sleep(100.milliseconds)
    c1.send(i)
  end
  c1.close
end

spawn do
  loop do
    if i = c1.receive?
      puts i
    else
      c2.send(nil)
    end
  end
end

c2.receive
puts "Done"

```

could

```auto
  loop do
    if i = c1.receive?
      ...
    end
  end

```

be replaced by something like:

```auto
c1.each do |item|
   puts item
end

```

perhaps via a macro

(Obviously , the inspiration is the iteration over a channel with a “for x:= range c1”) in Go.

---

<div class="post-metadata">

**Author:** ![jgaskins](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jgaskins/32/2449_2.png) [@jgaskins](https://forum.crystal-lang.org/u/jgaskins)\
**Post date:** [November 28, 2021, 12:03am UTC](https://forum.crystal-lang.org/t/in-the-following-snippet-producer-receiver-using-channel-would-it-be-possible-to-iterate-the-channel-instead-of-using-loop-followed-by-if-perhaps-with-a-macro/4097/2 "2021-11-28T00:03:30Z")

</div>

Crystal’s stdlib `Channel` isn’t meant to be used that way, but it _can_ be with `select` (very similar in concept to Go’s `select`):

```crystal
loop do
  select
  when value = channel.receive
    yield value
  else
    break
  end
end

```

Could probably have an `Enumerable` object for this:

```crystal
channel = Channel(String).new(10)

5.times { |i| channel.send i.to_s }

doubled = channel.range.map do |string|
  string * 2
end

pp doubled: doubled

class Channel
  def range
    Range.new(self)
  end

  struct Range(T)
    include Enumerable(T)

    def initialize(@channel : Channel(T))
    end

    def each
      loop do
        select
        when value = @channel.receive
          yield value
        else
          break
        end
      end
    end
  end
end

```

Keep in mind, though, that `select` on channels at a high-enough volume may not be feasible. Since stdlib channels need to be extremely flexible, they aren’t optimized for single-consumer workloads. Specifically, they can be consumed by any number of fibers safely, but “safe” doesn’t mean “non-blocking” and that safety comes at a performance cost.

If you just need to be able to consume a channel from a single fiber while other fibers write to it, I created a shard a while back called [`mpsc` (multi-producer/single-consumer)](https://github.com/jgaskins/mpsc) optimized for this purpose. Checking if the channel can be read without blocking (via `receive?`) involves no heap allocations and [the benchmark](https://github.com/jgaskins/mpsc/blob/master/benchmarks/mpsc_vs_select.cr) results are pretty wild:

```auto
➜ mpsc git:(master) ITERATIONS=1 crystal run --release benchmarks/mpsc_vs_select.cr
Empty channel
MPSC::Channel 430.59M ( 2.32ns) (± 2.00%) 0.0B/op fastest
      Channel 6.71M (149.01ns) (± 0.92%) 288B/op 64.16× slower

```

The difference with a larger number of iterations per block invocation gets even more extreme:

```auto
➜ mpsc git:(master) ✗ ITERATIONS=1000 crystal run --release benchmarks/mspsc_vs_select.cr
Empty channel
MPSC::Channel 1.06M (941.00ns) (± 1.33%) 0.0B/op fastest
      Channel 6.71k (148.94µs) (± 0.61%) 281kB/op 158.28× slower

```
