本文简要介绍ruby语言中 Kernel.select
的用法。
用法
select(read_array [, write_array [, error_array [, timeout]]]) → array or nil
调用 select(2) 系统调用。它监视给定的 IO
对象数组,等待一个或多个 IO
对象准备好读取、准备好写入并分别有未决异常,并返回一个包含这些 IO
对象数组的数组。如果给出可选的timeout
值并且在timeout
秒内没有 IO
对象准备好,它将返回nil
。
IO.select
查看 IO
对象的缓冲区以测试可读性。如果 IO
缓冲区不为空, IO.select
会立即通知可读性。此 “peek” 仅发生在 IO
对象上。对于 IO-like 对象(例如 OpenSSL::SSL::SSLSocket
)不会发生这种情况。
使用 IO.select
的最佳方法是在 read_nonblock、write_nonblock 等非阻塞方法之后调用它。这些方法引发了一个由 IO::WaitReadable
或 IO::WaitWritable
扩展的异常。模块通知调用者应该如何等待 IO.select
。如果引发 IO::WaitReadable
,调用者应该等待读取。如果引发 IO::WaitWritable
,调用者应该等待写入。
因此,可以使用 read_nonblock 和 IO.select
模拟阻塞读取(readpartial),如下所示:
begin
result = io_like.read_nonblock(maxlen)
rescue IO::WaitReadable
IO.select([io_like])
retry
rescue IO::WaitWritable
IO.select(nil, [io_like])
retry
end
特别是,非阻塞方法和 IO.select
的组合对于 IO
类对象(如 OpenSSL::SSL::SSLSocket
)是首选。它具有to_io 方法来返回底层 IO
对象。 IO.select
调用to_io获取要等待的文件说明符。
这意味着 IO.select
通知的可读性并不意味着 OpenSSL::SSL::SSLSocket
对象的可读性。
最可能的情况是 OpenSSL::SSL::SSLSocket
缓冲了一些数据。 IO.select
看不到缓冲区。因此,当 OpenSSL::SSL::SSLSocket#readpartial
不阻塞时, IO.select
可以阻塞。
但是,存在几种更复杂的情况。
SSL 是一种记录序列的协议。记录由多个字节组成。因此,SSL 的远程端发送部分记录, IO.select
通知可读性但 OpenSSL::SSL::SSLSocket
无法解密字节并且 OpenSSL::SSL::SSLSocket#readpartial
将阻塞。
此外,远程端可以请求 SSL 重新协商,这会强制本地 SSL 引擎写入一些数据。这意味着 OpenSSL::SSL::SSLSocket#readpartial
可能会调用 write 系统调用并且它可以阻塞。在这种情况下, OpenSSL::SSL::SSLSocket#read_nonblock
引发 IO::WaitWritable
而不是阻塞。因此,调用者应该等待准备好写,如上例所示。
当多个进程从一个流中读取时,非阻塞方法和 IO.select
的组合对于 tty、管道套接字套接字等流也很有用。
最后,Linux 内核开发人员不保证 select(2) 的可读性意味着即使对于单个进程也可以遵循 read(2) 的可读性。请参阅 GNU/Linux 系统上的 select(2) 手册。
在 IO#readpartial
之前调用 IO.select
可以正常工作。但是,这不是使用 IO.select
的最佳方式。
select(2) 通知的可写性不显示可写的字节数。 IO#write
方法阻塞,直到给定的整个字符串被写入。因此,在 IO.select
通知可写性后,IO#write(two or more bytes)
可以阻塞。需要 IO#write_nonblock
以避免阻塞。
可以使用 write_nonblock 和 IO.select
模拟阻塞写入(写入),如下所示: IO::WaitReadable
还应该在 OpenSSL::SSL::SSLSocket
中为 SSL 重新协商而拯救。
while 0 < string.bytesize
begin
written = io_like.write_nonblock(string)
rescue IO::WaitReadable
IO.select([io_like])
retry
rescue IO::WaitWritable
IO.select(nil, [io_like])
retry
end
string = string.byteslice(written..-1)
end
参数
示例
rp, wp = IO.pipe
mesg = "ping "
100.times {
# IO.select follows IO#read. Not the best way to use IO.select.
rs, ws, = IO.select([rp], [wp])
if r = rs[0]
ret = r.read(5)
print ret
case ret
when /ping/
mesg = "pong\n"
when /pong/
mesg = "ping "
end
end
if w = ws[0]
w.write(mesg)
end
}
产生:
ping pong
ping pong
ping pong
(snipped)
ping
相关用法
- Ruby Kernel.set_trace_func用法及代码示例
- Ruby Kernel.syscall用法及代码示例
- Ruby Kernel.sprintf用法及代码示例
- Ruby Kernel.srand用法及代码示例
- Ruby Kernel.system用法及代码示例
- Ruby Kernel.sleep用法及代码示例
- Ruby Kernel.spawn用法及代码示例
- Ruby Kernel.local_variables用法及代码示例
- Ruby Kernel.Integer用法及代码示例
- Ruby Kernel.binding用法及代码示例
- Ruby Kernel.frozen?用法及代码示例
- Ruby Kernel.`cmd`用法及代码示例
- Ruby Kernel.autoload用法及代码示例
- Ruby Kernel.loop用法及代码示例
- Ruby Kernel.Hash用法及代码示例
- Ruby Kernel.caller用法及代码示例
- Ruby Kernel.exit!用法及代码示例
- Ruby Kernel.trap用法及代码示例
- Ruby Kernel.String用法及代码示例
- Ruby Kernel.then用法及代码示例
- Ruby Kernel.Pathname用法及代码示例
- Ruby Kernel.yield_self用法及代码示例
- Ruby Kernel.BigDecimal用法及代码示例
- Ruby Kernel.raise用法及代码示例
- Ruby Kernel.test用法及代码示例
注:本文由纯净天空筛选整理自ruby-lang.org大神的英文原创作品 Kernel.select。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。