I have a select statement that sends data, and looks like this
select
when @my_channel.send data
In the above expression, data
is evaluated at the start of the select
statement, before @my_channel
could be sent to without blocking. I’d really like to be able to process the data to be sent when @my_channel
becomes sendable, before sending it. I don’t see any way to do this given the present implementation of select
.
In pseudocode, what I’d like to do is:
select
sendable @my_channel
data = some_processing
@my_channel.send data
What are you trying to, overall, do? It feels like data
could simply be a Proc
that you execute when needed.
I tried @my_channel.send Deque#to_a
, with the select
in a loop and another when
statement filling up the Deque. That didn’t work as expected. I suppose I might be able to use the select
primitives that are methods of Channel
, but there is a 2018 PR to document them that was rejected because they are internal.
I think I could do this using Channel#select(my_channel1.send_select_action, my_channel2.receive_select_action)
followed by a case
based on the argument index returned by Channel#select
. But that’s using undocumented functions not meant for the hoi polloi.
I don’t think you will be able to do that. Is equivalent to trying to know if a channel.send action will block you or not: you want to enqueue certain data you don’t know if the channel is “free”.
Suppose you know a channel is free to receive data, between that moment and the moment you actually have the data to send the situation could’ve change. So you are back to square one.
What are you trying to do with that queue? If its data is not only send to the channel, what is are you doing with it?
1 Like
@bcardiff Yes, you are right, I would need my modified select
action to take a lock on the channel before it wakes the waiting fiber, and then release the lock when the receive or send action completes (it would be a block). This is a desirable feature IMO, but perhaps should use its own version of Channel
, because the existing Channel
only uses a SpinLock
, and it’s bad to hold a SpinLock
for that long. I really want something like Mutex#synchronize
for this.
Why did I need it? It happened that I was using a Deque
to manage my data, and I wanted to call #to_a
before sending it. In the current implementation, this would throw away memory in a loop.
As it happens, I was making a higher-level IPC object - one that is implemented on top of Channel
and behaves slightly differently from Channel
. If I wanted ultimate performance, I would reimplement Channel
with my desired behavior. IMO there is room for shards full of such things.
1 Like