[#70257] [Ruby trunk - Feature #11420] [Open] Introduce ID key table into MRI — ko1@...

Issue #11420 has been reported by Koichi Sasada.

11 messages 2015/08/06

[ruby-core:70545] [Ruby trunk - Feature #10600] [PATCH] Queue#close

From: ko1@...
Date: 2015-08-22 09:09:52 UTC
List: ruby-core #70545
Issue #10600 has been updated by Koichi Sasada.

Assignee set to Koichi Sasada

Thank you for your great survey. I want to introduce Queue#close in Ruby 2.3.

Just now I'm not sure it is okay to provide think Queue#close(token) API because there are no similar examples in Ruby.

The followings are summary of your survey.

| language | API      | deq from empty queue after close?                                 |
|----------|----------|-------------------------------------------------------------------|
| Java     | N/A      |                                                                   |
| go       | Close    | Run-time panics (return error) https://golang.org/ref/spec#Close  |
| C++      | close()  | return queue_op_status::closed (element is returned by reference) |
| closure  | close!   | return nil                                                        |

| Ruby's similar operation            | What happen after read from empty stream? |
|-------------------------------------|-------------------------------------------|
| File#read                           | return nil                                |
| File#read_nonblock()                | raise EOFError                            |
| File#read_nonblock(exception: false)| return nil                                |
| File#gets                           | return nil                                |

Options:
1. Queue#close(token)
2. Queue#close() and raise on deq from empty closed Queue
3. Queue#close() and return nil from empty closed Queue (raise by deq(nonblock=true))
4. Queue#close(exc) -> (2) if exc is not nil, (3) if exc is nil
5. Queue#close(exception: true/false) -> (2) if exception is true (specific exception, such as ClosedQueueError < StopIteration), (3) if exception is false
6. Queue#close() and provide Queue#deq(exception: false)

(3) is similar to IO's gets/read/...
(6) is similar to IO's read_nonblock.

I think (1) is over-spec. (4) should be nice than (1). But I like (5) because it is more simple.


----------------------------------------
Feature #10600: [PATCH] Queue#close
https://bugs.ruby-lang.org/issues/10600#change-53952

* Author: John Anderson
* Status: Open
* Priority: Normal
* Assignee: Koichi Sasada
----------------------------------------
In a multiple-producer / multiple-consumer situation using blocking enq and deq, closing a queue cleanly is difficult. It's possible using a queue poison token, but unpleasant because either producers have to know how to match up number of poison tokens with number of consumers, or consumers have to keep putting the poison back into the queue which complicates testing for empty and not blocking on deq.

This patch (from trunk at b2a128f) implements Queue#close which will close the queue to producers, leaving consumers to deq the remaining items. Once the queue is both closed and empty, consumers will not block. When an empty queue is closed, all consumers blocking on deq will be woken up and given nil.

With Queue#close, clean queue shutdown is simple:

~~~ ruby
queue = SizedQueue.new 1000

consumer_threads = lots_of.times.map do
  Thread.new do
    while item = queue.pop
      do_work item
    end
  end
end

source = somewhat_async_enumerator

producer_threads = a_few.times.map do
  Thread.new do
    loop{queue << source.next}
  end
end

producer_threads.each &:join
queue.close
consumer_threads.each &:join
~~~


---Files--------------------------------
queue-close.diff (5.18 KB)
queue-close-2.diff (10.2 KB)
patch-25f99aef.diff (25.2 KB)
queue_benchmark.rb (2.95 KB)


-- 
https://bugs.ruby-lang.org/

In This Thread

Prev Next