Forum: Ruby input without blocking

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
5d8a5bba2317da6231774d4d1ddef1d8?d=identicon&s=25 yahn (Guest)
on 2006-03-27 04:51
How do you do something like gets but without blocking?  All I want to
do is try to see if anything was input and if it wasn't then just go on
running the rest of my code.
C63e105d68d1e5e8dcba755d15de7a22?d=identicon&s=25 Eustáquio Rangel (taq)
on 2006-03-27 06:17
(Received via mailing list)
> How do you do something like gets but without
> blocking?  All I want to
> do is try to see if anything was input and if it
> wasn't then just go on
> running the rest of my code.

Maybe you're looking for:

taq@taq$ irb
irb(main):001:0> require "timeout"
=> true
irb(main):002:0> s =
irb(main):003:0* begin
irb(main):004:1*    timeout(5) do
irb(main):005:2*       gets
irb(main):006:2>    end
irb(main):007:1> rescue TimeoutError
irb(main):008:1>    ""
irb(main):009:1> end

If on 5 seconds you don't type something, s will be an
empty string.

Best regards,
58479f76374a3ba3c69b9804163f39f4?d=identicon&s=25 Eric Hodel (Guest)
on 2006-03-27 09:17
(Received via mailing list)
On Mar 26, 2006, at 6:52 PM, yahn wrote:

> How do you do something like gets but without blocking?  All I want to
> do is try to see if anything was input and if it wasn't then just
> go on
> running the rest of my code.

Use threads.

In one thread perform your IO.  In your other thread do whatever it
is you'd like to do while waiting for IO.

--
Eric Hodel - drbrain@segment7.net - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com
5d8a5bba2317da6231774d4d1ddef1d8?d=identicon&s=25 Brian Yahn (yahn)
on 2006-03-27 22:04
Eric Hodel wrote:
> On Mar 26, 2006, at 6:52 PM, yahn wrote:
>
>> How do you do something like gets but without blocking?  All I want to
>> do is try to see if anything was input and if it wasn't then just
>> go on
>> running the rest of my code.
>
> Use threads.
>
> In one thread perform your IO.  In your other thread do whatever it
> is you'd like to do while waiting for IO.
>
> --
> Eric Hodel - drbrain@segment7.net - http://blog.segment7.net
> This implementation is HODEL-HASH-9600 compliant
>
> http://trackmap.robotcoop.com

Ok thats one way to do it, but doesn't ruby have an actual way of just
seeing if any input has been performed?  Unnecessary threads will just
slow down the program.
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2006-03-27 22:53
(Received via mailing list)
brian yahn wrote:
>> is you'd like to do while waiting for IO.
>
A thread won't cost much if it is just waiting for input.

If the other tasks that are being handled by your program are driven by
IO, then you could use select from a single one thread. (That's more or
less what is going on when you have multiple ruby threads each handling
their own IO.)

Or you could use select with a timeout of 0 to check if input is
available on $stdin.

print "type something> "; $stdout.flush
loop do
  sleep 0.1; print "."; $stdout.flush
  if IO.select([$stdin], [], [], 0)
    str = $stdin.gets
    break unless str
    puts "You typed #{str.inspect}"
    print "type something> "; $stdout.flush
  end
end

The #sleep call and the print "." is just to emulate the effect of the
program running while the user is typing.

However, I expect that it will be easier to make the program feel
responsive if you use threads, and let ruby's thread scheduler handle
the timing.
72a9d617a5a05a84bdd3e9c06afe38ef?d=identicon&s=25 unknown (Guest)
on 2006-03-28 00:59
(Received via mailing list)
There should be methods on Unix and Linux using select or something
like that.  At least Unix and Posix provide the functionality you are
asking already at OS-level, so it is just a matter of if and how to
access this from Ruby.  I would prefer this OS-dependent approach.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-03-28 01:12
(Received via mailing list)
On Tue, 28 Mar 2006 karl_brodowsky@yahoo.com wrote:

> There should be methods on Unix and Linux using select or something like
> that.  At least Unix and Posix provide the functionality you are asking
> already at OS-level, so it is just a matter of if and how to access this
> from Ruby.  I would prefer this OS-dependent approach.

here ya go:

     harp:~ > cat a.rb
     require 'io/wait'

     puts Time.now
     STDIN.wait unless STDIN.ready?
     puts Time.now

     puts STDIN.gets

     harp:~ > cat b.rb
     sleep 2
     puts 42


     harp:~ > ruby b.rb | ruby a.rb
     Mon Mar 27 16:10:42 MST 2006
     Mon Mar 27 16:10:44 MST 2006
     42


kind regards.

-a
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 unknown (Guest)
on 2006-03-28 01:24
(Received via mailing list)
On Mar 27, 2006, at 6:11 PM, ara.t.howard@noaa.gov wrote:


>     STDIN.wait unless STDIN.ready?

I might be missing something here but couldn't another thread
read any pending input after STDIN.ready? has returned true and
before STIN.wait is called?  That would result in STDIN.wait
blocking for more input, correct?


Gary Wright
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-03-28 01:35
(Received via mailing list)
On Tue, 28 Mar 2006 gwtmp01@mac.com wrote:

>
> On Mar 27, 2006, at 6:11 PM, ara.t.howard@noaa.gov wrote:
>
>
>>     STDIN.wait unless STDIN.ready?
>
> I might be missing something here but couldn't another thread
> read any pending input after STDIN.ready? has returned true and
> before STIN.wait is called?  That would result in STDIN.wait
> blocking for more input, correct?

sort of - STDIN.wait simply returns when a read from the io would not
block,
so having input OR being at the end of file, for example, might cause it
to
return.  thread safety must indeed be handled too.

-a
5d8a5bba2317da6231774d4d1ddef1d8?d=identicon&s=25 Brian Yahn (yahn)
on 2006-03-28 05:31
Wouldn't this:

     puts Time.now
     STDIN.wait unless STDIN.ready?
     puts Time.now

     puts STDIN.gets

block until something is input?  Thats not what I want to do.  Unless
wait is deceiving, I don't see how this would do what I want.
5c841628b56df3a68984986e9f095d01?d=identicon&s=25 Andrew Johnson (andrew)
on 2006-03-28 06:40
(Received via mailing list)
On Mon, 27 Mar 2006 11:52:10 +0900, yahn <yahn15@hotmail.com> wrote:
> How do you do something like gets but without blocking?  All I want to
> do is try to see if anything was input and if it wasn't then just go on
> running the rest of my code.

I was going to suggest using the Fcntl extension to set the non-blocking
bit on the filehandle as an alternative, but it appears to not be
working
(at least on my linux box). That is to say, this script sits and waits
for
input:

  require 'fcntl'

  flags = STDIN.fcntl(Fcntl::F_GETFL, 0)
  flags |= Fcntl::O_NONBLOCK
  STDIN.fcntl(Fcntl::F_SETFL, flags)

  a = STDIN.gets
  puts "You got #{a}"


Whereas the equivalent Perl script:

  use Fcntl;

  $flags = fcntl(STDIN,F_GETFL,0);
  $flags |= O_NONBLOCK;
  fcntl(STDIN,F_SETFL,O_NONBLOCK);

  $foo = <STDIN>;
  print "Got $foo\n";

doesn't block and finishes immediately.

andrew
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-03-28 06:43
(Received via mailing list)
On Tue, 28 Mar 2006, brian yahn wrote:

> Wouldn't this:
>
>     puts Time.now
>     STDIN.wait unless STDIN.ready?
>     puts Time.now
>
>     puts STDIN.gets
>
> block until something is input?  Thats not what I want to do.  Unless
> wait is deceiving, I don't see how this would do what I want.


wait takes a timeout.

you may want to try io/nonblock:

   harp:~ > cat a.rb
   require 'io/nonblock'
   p STDIN.nonblock{ STDIN.gets }


   harp:~ > ruby a.rb </dev/null
   nil


   harp:~ > ruby a.rb <a.rb
   "require 'io/nonblock'\n"


but you have to realize there really are no ways to tell 'if something
was
input' - only ways to tell if a read would block.  consider

   harp:~ > cat b.rb
   print 42
   sleep

   harp:~ > ruby b.rb|ruby a.rb
   ...


but we're blocking because we used 'gets' which reads till newline.  the
only
other alternatives are giving a number of bytes to read or using
something like
readpartial

   harp:~ > cat a.rb
   require 'io/nonblock'
   p STDIN.nonblock{ STDIN.readpartial(2) }

   harp:~ > cat b.rb
   STDOUT.sync = true
   print 42
   sleep

   harp:~ > ruby b.rb|ruby a.rb
   "42"
   ...

but even here you hang.


what are you trying to do exactly?  the std unix practive of giving '-'
as a
command line arg when stdin is meant to be read can neatly avoid this
problem.

regards.


-a
5d8a5bba2317da6231774d4d1ddef1d8?d=identicon&s=25 Brian Yahn (yahn)
on 2006-03-28 06:47
I'm just trying to get the characters being input into the program and
run it at the same time without a thread.  A thread is not needed in c++
to do this, so I figured it wouldn't be needed in ruby.  Maybe ruby
isn't as great as I first thought.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-03-28 06:53
(Received via mailing list)
On Tue, 28 Mar 2006, Andrew Johnson wrote:

>  require 'fcntl'
>
>
> andrew

this seems like a bug...  maybe a post to ruby-core?

-a
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-03-28 07:17
(Received via mailing list)
On Tue, 28 Mar 2006, brian yahn wrote:

> I'm just trying to get the characters being input into the program and
> run it at the same time without a thread.  A thread is not needed in c++
> to do this, so I figured it wouldn't be needed in ruby.  Maybe ruby
> isn't as great as I first thought.

probably not:


   fortytwo :~ > cat a.rb
   require 'io/nonblock'
   p STDIN.nonblock{ STDIN.gets }

   fortytwo :~ > ruby a.rb</dev/null
   nil

   fortytwo :~ > ruby a.rb<a.rb
   "require 'io/nonblock'\n"


-a
5c841628b56df3a68984986e9f095d01?d=identicon&s=25 Andrew Johnson (andrew)
on 2006-03-28 07:44
(Received via mailing list)
On Tue, 28 Mar 2006 13:53:12 +0900, ara.t.howard@noaa.gov
<ara.t.howard@noaa.gov> wrote:

>
> this seems like a bug...  maybe a post to ruby-core?

Probably a good idea -- unless no-one else is seeing this behaviour?

andrew
31af45939fec7e3c4ed8a798c0bd9b1a?d=identicon&s=25 Matthew Smillie (Guest)
on 2006-03-28 10:58
(Received via mailing list)
On Mar 28, 2006, at 5:48, brian yahn wrote:

> I'm just trying to get the characters being input into the program and
> run it at the same time without a thread.  A thread is not needed
> in c++
> to do this.

In the simple case, a thread isn't needed anywhere:

--- Ruby ---

STDIN.print "Type away: "
STDIN.flush
10.times do
   #something pointlessly time-consuming
end
input = STDIN.gets
puts "You typed: #{input}"

--- C++ ---

#include <iostream>
#include <string>
using namespace std;

int main() {
   cout >> "Type away: "
   for (int i = 0; i < 10; i++) {
     // something pointlessly time-consuming
   }
   string input;
   cin >> input;
   cout << "You typed: " << input << "\n"
   return 0;
}


No thread, no blocking (unless the typist is particularly slow).  The
C++ version, if you run it, will only grab one word from the input,
but as an example I'm sure you get the idea.

Apart from that sort of thing, I'd be interested to know exactly how C
++ doesn't require a separate thread/process to handle input.  I
suspect that it's simply just being created by whatever library
you're using.

matthew smillie.
31af45939fec7e3c4ed8a798c0bd9b1a?d=identicon&s=25 Matthew Smillie (Guest)
on 2006-03-28 11:02
(Received via mailing list)
On Mar 28, 2006, at 9:57, Matthew Smillie wrote:

> STDIN.print "Type away: "
> STDIN.flush

Those should, of course, read "STDOUT" rather than "STDIN".

mea culpa.
C0ec5a090e5df61f717849e6846d5246?d=identicon&s=25 Ernest Obusek (Guest)
on 2006-03-28 18:21
(Received via mailing list)
I wrote a little timer application and I would like it to play a
sound when the timer has counted down to 0.  I looked for a beep
method in the pickaxe book but couldn't find a standard one.  I
searched the web for information about sound support for Ruby and
found something called FMod that runs on my Mac but doesn't seem to
have Ruby support.  I know I can try to wrap that up for Ruby but
before making the effort I thought I'd ask here if anyone knows of
something already available and easy to use for playing sounds in
Ruby on a Mac PowerBook.  Oh, I also looked at RUDL but Mac support
looks sketchy and I'd rather go with FMod if necessary.

Thanks,

Ernest
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-03-28 18:47
(Received via mailing list)
On Mar 28, 2006, at 10:21 AM, Ernest Obusek wrote:

> I wrote a little timer application and I would like it to play a
> sound when the timer has counted down to 0.

If your needs are very simple, you could print the alarm character:

   print "\a"

James Edward Gray II
5f7864fec0933c58fee8b96e1e9db27d?d=identicon&s=25 Alpha Chen (Guest)
on 2006-03-28 18:52
(Received via mailing list)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Mar 28, 2006, at 11:21 AM, Ernest Obusek wrote:

> I wrote a little timer application and I would like it to play a
> sound when the timer has counted down to 0.

You could always try RubyCocoa. From the main page (http://
rubycocoa.sourceforge.net/doc/):

The next script plays all the system sounds.

require 'osx/cocoa'
snd_files =`ls /System/Library/Sounds/*.aiff`.split
snd_files.each do |path|
   snd = OSX::NSSound.alloc.
     initWithContentsOfFile_byReference (path, true)
   snd.play
   sleep 0.5
end

Alpha Chen
0xCDE1AD58 on keyserver.net


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (Darwin)

iD8DBQFEKWnCTm5GrM3hrVgRAj3zAJ4tiRkOE4YgVoQQYP3f5opN7yjgmACgmpSK
dRXzk95XsgMd4kJvuoHq+WY=
=CMM9
-----END PGP SIGNATURE-----
2e34f386b20cb7c11c4204d699babd78?d=identicon&s=25 Chris Alfeld (Guest)
on 2006-03-28 18:55
(Received via mailing list)
exec "osascript -e 'beep 1'"

Or, better yet, get ahold of osx/aeosa and use those bindings.
5d8a5bba2317da6231774d4d1ddef1d8?d=identicon&s=25 Brian Yahn (yahn)
on 2006-03-28 21:42
Chris Alfeld wrote:
> exec "osascript -e 'beep 1'"
>
> Or, better yet, get ahold of osx/aeosa and use those bindings.

cin >> blocks.  cin is basically the same thing as gets.  I guess I will
just use a thread, but it seems kind of pointless to make the processor
have to schedule just for input.
C0ec5a090e5df61f717849e6846d5246?d=identicon&s=25 Ernest Obusek (Guest)
on 2006-03-28 22:05
(Received via mailing list)
This is awesome!  Thank you!
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-03-29 06:26
(Received via mailing list)
On Mar 28, 2006, at 11:55 AM, Chris Alfeld wrote:

> exec "osascript -e 'beep 1'"

I hope you never want to return after beeping
2e34f386b20cb7c11c4204d699babd78?d=identicon&s=25 Chris Alfeld (Guest)
on 2006-03-29 06:47
(Received via mailing list)
It isn't so much that I never want to return as that I want to become
one with the osascript and exit after beeping =)

My bad, meant 'system' not 'exec'; too  much tcl in my past.
This topic is locked and can not be replied to.