Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about using select in loops #64

Open
ytoh opened this issue Dec 15, 2024 · 2 comments
Open

Question about using select in loops #64

ytoh opened this issue Dec 15, 2024 · 2 comments

Comments

@ytoh
Copy link

ytoh commented Dec 15, 2024

Hi team!

I am enjoying the results of the work you have done on this library. Thank you for it. I have one question. I am trying to drain multiple channels into one and when I use Select#selectOrClosed in a loop I encounter a situation that from the point a single channel gets closed I only ever get a ChannelDone out. The following is the behavior captured in a unit test.

  @Test
  void test_only_done() throws InterruptedException {
    var ch1 = new Channel<String>(1);
    var ch2 = new Channel<String>(1);
    ch1.done();
    ch2.send("hello");
    ch2.done();

    for (int i = 0; i < 100; i++) {
      var result = Select.selectOrClosed(ch1.receiveClause(), ch2.receiveClause());
      assertInstanceOf(ChannelDone.class, result);
    }
  }

If I want to avoid this problem I have to remove closed channels from the list being selected on every iteration. I captured this in a unit test as well:

@Test
  void test_select_with_remove() throws InterruptedException {
    var ch1 = new Channel<String>(1);
    var ch2 = new Channel<String>(1);
    var output = new Channel<String>(2);
    ch1.done();
    ch2.send("hello");
    ch2.done();

    var receiveClauses = Stream.of(ch1, ch2).map(Channel::receiveClause).toList();
    do {
      var o = Select.selectOrClosed(receiveClauses.toArray(new SelectClause[0]));
      if (!(o instanceof ChannelDone)) {
        output.send((String) o);
      }
      receiveClauses =
          Stream.of(ch1, ch2)
              .filter(ch -> !ch.isClosedForReceive())
              .map(Channel::receiveClause)
              .toList();
    } while (!receiveClauses.isEmpty());
    output.done();

    assertEquals("hello", output.receive());
    assertInstanceOf(ChannelDone.class, output.receiveOrClosed());
  }

I have to loop through all of the channels because unfortunately the ChannelDone signal does not have a reference to the channel that it relates to :(.

My question is: Is this the correct behavior or am I doing something silly?
Thanks!

@adamw
Copy link
Member

adamw commented Dec 16, 2024

Yes, it's a shortcoming I'm hoping to address sooner rather than later :) That's how we're using channels too (filtering out the "done" ones if needed)

@adamw
Copy link
Member

adamw commented Dec 16, 2024

related: softwaremill/ox#201

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants