我正在写一个线程服务器中的套接字(此刻在MRI上运行)。使用以下代码执行此操作:
public static char[] getCharsFromBytes(byte[] bytes, int index, int count) {
char[] charArr = getCharsFromBytes(bytes);
char[] result = new char[count];
for (int i = 0; i < count; i++) {
result[i] = charArr[i + startIndex];
}
return result;
}
它的要点是,如果我有一个WaitWritable(套接字已饱和),我希望运行此服务器的服务器抢占另一个线程。这里begin
num_bytes_written = socket.write_nonblock(chunk)
if num_bytes_written < chunk.bytesize
chunk = chunk[num_bytes_written..-1]
raise Errno::EINTR
end
rescue IO::WaitWritable, Errno::EINTR
Thread.pass if server_is_threaded
IO.select(nil, [socket])
retry
rescue Errno::EPIPE
return
end
是个好主意,或者如果我的主题是Thread.pass
,那么MRI会自动抢占其他内容吗?
答案 0 :(得分:1)
线程始终运行,直到超过其时间片或进入等待状态为止。在支持线程优先级和抢占的系统上,较高优先级的线程也可以抢占具有较低优先级的运行线程,但这取决于系统。进入等待状态意味着线程正在等待某个事件发生,并且直到该事件发生后才可以运行。 I / O事件或计时事件,例如休眠一定时间。
Thread.pass
是大多数其他编程语言和操作系统称为yield的内容,但是,由于显而易见的原因,在Ruby中使用该术语当然会产生很大的误导。这意味着您告诉操作系统将线程视为超出其时间片,使其他线程有机会立即运行,而不必等待线程用完其所有时间片,等待或等待。抢先。当您的线程在屈服时保持处于可运行状态(不认为正在等待任何东西)时,它可以立即再次运行,因此,由于线程调度程序可能会认为您的线程仍处于确定下一个运行线程的最佳选择(特别是如果所有其他可运行线程的优先级都较低时)。
但是如果IO.select
必须阻塞,这将使您的线程进入等待状态,然后它将不再可用于运行,因此在这种情况下,线程调度程序必须无论如何都要选择另一个线程,并且记录在案:
调用select(2)系统调用。它监视给定的IO对象数组,等到,直到一个或多个IO对象准备好读取,准备好写入并有未决异常,然后返回包含这些IO对象数组的数组
等待始终意味着线程停止运行,并且只要线程停止运行,其他一些可运行线程就会接管。
但是,如果您的意图是始终在发生错误的情况下为另一个线程提供运行的机会,则无论select
是否会阻塞(因为它不必阻塞,直到现在为止) select
被调用,套接字可以再次被写入,然后它不会被阻塞),那么调用Thread.pass
可能真的很有意义。但是大多数程序员可能不会在那种情况下调用它,好像select
不会阻塞一样,您通常希望立即再次重复执行写操作(在同一时间段内,如果可能的话,如果没有,则您的线程会无论如何通过。