Navigation Menu

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

receive from channel with timeout #2990

Closed
kostya opened this issue Jul 13, 2016 · 12 comments
Closed

receive from channel with timeout #2990

kostya opened this issue Jul 13, 2016 · 12 comments

Comments

@kostya
Copy link
Contributor

kostya commented Jul 13, 2016

how to do that?
in go i can

select {
case <-ch:
    // a read from ch has occurred
case <-timeout:
    // the read from ch has timed out
}
@asterite
Copy link
Member

I think we'll eventually have a select expression: #688

Right now you need to do it in an ugly way: https://github.com/crystal-lang/crystal/blob/master/samples/channel_select.cr

Of course for timeout you need to spawn, sleep and then send through a channel. @waj wants things other than channels to be able to be used in select, so maybe there will be a simpler way to do this in the future.

@asterite
Copy link
Member

Check https://github.com/crystal-lang/crystal/blob/master/samples/channel_select.cr

Eventually I think we'll have a select expression: #688

For timeout you need to spawn, sleep and then send through a channel, although @waj wanted this to be simpler, maybe things other than channels could be used in select, but I don't know.

@kostya
Copy link
Contributor Author

kostya commented Jul 13, 2016

what about this?

ch = Channel(Nil).new

spawn do
  sleep 10.seconds
  ch.timeout!
end

begin
  x = ch.receive
rescue Channel::Timeout
end

@asterite
Copy link
Member

Exceptions are slow, they shouldn't be used for control flow.

@ysbaddaden
Copy link
Contributor

Timeouts could be implemented in the receive_impl method of channels. The problem is how to report it to the blocked fiber. Maybe by returning an IO::Timeout? But then any ch.receive would have to be aware that it may receive en IO::Timeout...

@kostya
Copy link
Contributor Author

kostya commented Jul 14, 2016

add new method receive_timeout(10.seconds)

@asterite
Copy link
Member

It'll be something like this:

select
when value = ch.receive
  puts value
when sleep(10.seconds)
  puts "Timeout!"
end

The idea is that this gets rewritten, so a call like ch.receive would be ch.receive_op, and sleep would be sleep_op, or something like that, so select is somehow extensible. But these are just ideas in the air, we didn't think it thoroughly.

@kostya
Copy link
Contributor Author

kostya commented Jul 14, 2016

but what if someone send to channel later, what happen in this case? block forever?

@asterite
Copy link
Member

@kostya I don't know because I don't have much experience with channels and timeouts, but I guess on a timeout you'd close the channel so nothing else can be sent on it... maybe it depends on the specific scenario? Or else, we'd have to think how this is done in Go.

@ysbaddaden
Copy link
Contributor

This is a receive timeout, so it should merely mean: it expected to receive a message within X seconds but it didn't receive one. I think it's up to the developer to decide to close the channel or not, depending on its usage and expectations.

@kostya
Copy link
Contributor Author

kostya commented Jul 14, 2016

hm, if i can close the channel so there is no problem. sender should crash in this case.

@kostya
Copy link
Contributor Author

kostya commented Jul 14, 2016

this is nice now i use:

spawn do
  sleep 10
  ch.close
end

spawn do
  sleep 20
  ch.send 1 # => Exception
end

res = ch.receive rescue "timeouted"

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

No branches or pull requests

3 participants