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

Add ArrayQueue #189

Merged
merged 5 commits into from Jan 21, 2019
Merged

Add ArrayQueue #189

merged 5 commits into from Jan 21, 2019

Conversation

ghost
Copy link

@ghost ghost commented Oct 1, 2018

This is a port of crossbeam-channel's bounded queue.

@jeehoonkang
Copy link
Contributor

I couldn't find where we did, but I recall that we discussed the three dimensions of the flavors of queues:

  • bounded/unbounded
  • multi/single producer
  • multi/single consumer

I think the circular buffer will be a good implementation for all flavors of bounded queues (as this PR suggests) and unbounded spsc/spmc queues (and also work-stealing deques). The segmented queue would be a good one for unbounded mpsc/mpmc queues, guess.

So I'd like to reorganize the code/crates in such a way that all those flavors (while not every combination may be practical) are addressed in Crossbeam with appropriate implementations. So I suggest:

  • Merge crossbeam-deque, this PR, and https://github.com/jeehoonkang/concurrent-circbuf to form crossbeam-circbuf, which provides all flavors of bounded queues and unbounded spsc/spmc queues, as well as work-stealing queues.
  • Introduce crossbeam-segqueue which provides unbounded mpmc segmented queues.
  • Rebase crossbeam-channel on the above sub-crates, if possible. We need @stjepang's opinion here :)
  • Expose recommended implementations in the root crate, e.g. in crossbeam::queue.

What do you think?

@ghost
Copy link
Author

ghost commented Nov 8, 2018

I think the circular buffer will be a good implementation for all flavors of bounded queues

I definitely want circular buffers in crossbeam, but they are primarily single-producer, aren't they? Correct me if I'm mistaken.

This is a bounded MPMC queue and Dmitry Vyukov's implementation is (to my knowledge) the best one for this specific purpose.

Merge crossbeam-deque, this PR, and jeehoonkang/concurrent-circbuf to form crossbeam-circbuf, which provides all flavors of bounded queues and unbounded spsc/spmc queues, as well as work-stealing queues.

I'm beginning to think that perhaps we should keep crossbeam-deque as a distinct crate for building schedulers. The reason is that schedulers often need the special steal-half method (and perhaps some others) and I find that these special features often clash with some optimizations we'd otherwise like to make.

This reminds me of the difference between channels (high-level with extra features like disconnection and blocking operations) and queues (low-level and focused on raw speed).

Perhaps crossbeam-deque should be a higher-level crate with extra features like steal-half and a choice between FIFO and LIFO strategies (important in schedulers like Tokio and Rayon), while crossbeam-circbuf would be more primitive, always FIFO, and focused on performance.

How does that sound?

Introduce crossbeam-segqueue which provides unbounded mpmc segmented queues.

Yes, that sounds good! 👍 Although I'd personally prefer to collect all those data structures in crossbeam first, polish them up, and then next year decide what and how to move to separate crates. Perhaps next year we could also put some effort into stabilization and start considering breaking changes more seriously. :)

Expose recommended implementations in the root crate, e.g. in crossbeam::queue.

Yes!

By the way, what's the state of crossbeam-circbuf? If it is in a reasonable state, can we move it into this repository?

@ghost
Copy link
Author

ghost commented Nov 29, 2018

@jeehoonkang Ping. :)

@jeehoonkang
Copy link
Contributor

jeehoonkang commented Nov 29, 2018

I'm sorry, I didn't notice that its wait-on-me... May I ask if you could wait for me another week? Currently I'm very busy preparing for my next job. I'll be over by 7 December. Sorry.

@jeehoonkang
Copy link
Contributor

I'm happy with the implementation of ArrayQueue. Anyway, it's by Dmitry Vyukov!

Probably my main concern here is the organization of the crates. I can see that deque and channel are intended to be batteries-included data structures, while circbuf and *queue are intended to be barebone ones. I wonder if we can avoid functionally duplicated code as much as possible. More specifically, I wonder if (1) deque can be based on circbuf, and (2) channel can be based on various crates on queue. I think it'll be possible for deque, but I have no idea for channel.

As soon as this discussion is concluded, I'll send a PR on crossbeam-circbuf. AFAICT, it'll be in a good shape soon.

@ghost
Copy link
Author

ghost commented Dec 11, 2018

I wonder if (1) deque can be based on circbuf

It would be great if we can do that, although the steal_many operation in deque might cause issues. We'll see. :)

(2) channel can be based on various crates on queue.

I highly doubt it. There are two obstacles:

  • crossbeam-channel needs to perform operations in two steps. For example, its queues support the start_recv() operation which only allocates a slot in the queue. Then the caller needs to follow up with unsafe function read() that completes the operation. This is used by the internals of select!.

  • I want to use pointer tagging and index tagging to mark the channel as closed. This is a trick that simpler queues like ArrayQueue won't have implemented.

As soon as this discussion is concluded, I'll send a PR on crossbeam-circbuf.

I think we're okay with providing just three types of queues:

  • unbounded MPMC: SegQueue
  • bounded MPMC: ArrayQueue
  • unbounded SPMC: circbuf

This small set of queues would probably cover 99% of use cases.

Oh, and I just got an idea for a good naming scheme. Note:

  • BTreeMap is a map based on B tree.
  • HashMap is a map based on hashing.
  • VecDeque is a deque based on Vec (unbounded).
  • ArrayVec is a Vec based on array (bounded).

Similarly, our queues could be named:

  • ArrayQueue - a queue based on array (bounded; this PR).
  • ListQueue or SegQueue - a queue based on a linked list or segmented list of nodes.
  • VecQueue - a queue based on Vec (unbounded; circbuf).

I think VecQueue conveys how circbuf works really well because there is a growable buffer behind the data structure (just like in VecDeque).

One more additional node: While we could provide more specialized queues like SPSC queues based on ArrayQueue and SPSC queues based on circbuf, I think we don't need to. The benefits of such specialized queues are so small that it's not worth the added complexity, in my opinion.

Those three queue types could live in three crates. I'd be okay with crossbeam-arrayqueue, crossbeam-listqueue, and crossbeam-vecqueue.

@jeehoonkang
Copy link
Contributor

bors r+

Thanks!

@bors
Copy link
Contributor

bors bot commented Dec 25, 2018

Merge conflict

@ghost
Copy link
Author

ghost commented Jan 21, 2019

Rebased and updated the code to match latest crossbeam-channel.

bors r+

@bors
Copy link
Contributor

bors bot commented Jan 21, 2019

Merge conflict (retrying...)

bors bot added a commit that referenced this pull request Jan 21, 2019
189: Add ArrayQueue r=stjepang a=stjepang

This is a port of `crossbeam-channel`'s bounded queue.

Co-authored-by: Stjepan Glavina <stjepang@gmail.com>
@bors
Copy link
Contributor

bors bot commented Jan 21, 2019

Build succeeded

@bors bors bot merged commit 9c8503d into crossbeam-rs:master Jan 21, 2019
@ghost ghost deleted the array-queue branch January 21, 2019 15:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

1 participant