Thread.pass при использовании IO.select

Я пишу в сокет в многопоточном сервере (в данный момент работающем на МРТ). Делаем это с помощью следующего кода:

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

Суть в том, что я хочу, чтобы сервер, на котором это выполняется, выгружал другой поток, если у меня есть WaitWritable (сокет насыщен). Является Thread.pass хорошая идея здесь, или МРТ автоматически вытеснит что-то еще, если мой поток делает select()?

0 ответов

Поток всегда работает до тех пор, пока не превысит свой временной интервал или не перейдет в состояние ожидания. В системах, которые поддерживают приоритеты потоков и вытеснение, поток с более высоким приоритетом может также иметь возможность выгружать работающий поток с более низким приоритетом, но это зависит от системы. Переход в состояние ожидания означает, что поток ожидает некоторого события и не будет доступен для запуска до тех пор, пока это событие не произошло, например, событие ввода-вывода или событие синхронизации, например, спящий в течение определенного периода времени.

Thread.pass это то, что большинство других языков программирования и операционных систем называют уступчивым, но, конечно, использование этого термина в Ruby будет очень вводящим в заблуждение по очевидным причинам. Это означает, что вы приказываете операционной системе обращаться с вашим потоком так, как если бы его временной интервал был превышен, что дает другим потокам возможность работать немедленно, не дожидаясь, пока ваш поток израсходует все свои временные интервалы, ожидает или будет прерванным. Поскольку ваш поток остается в состоянии выполнения при выдаче (он не считается ожидающим чего-либо), он сразу же доступен для повторного запуска, поэтому не говорится, что другой поток вступит во владение, так как планировщик потока может считать, что ваш поток все еще лучший кандидат при принятии решения о том, какой поток следует запустить следующим (особенно, если все остальные выполняемые потоки имеют более низкий приоритет).

Но в случае IO.select должен блокировать, это переведет ваш поток в состояние ожидания, после чего он больше не будет доступен для запуска, поэтому в этом случае планировщик потока все равно должен выбрать другой поток, и это задокументировано:

Вызовы выберите (2) системный вызов. Он отслеживает заданные массивы объектов ввода-вывода, ожидает, пока один или несколько объектов ввода-вывода будут готовы для чтения, готовы к записи и имеют ожидающие исключения соответственно, и возвращает массив, содержащий массивы этих объектов ввода-вывода.

Ожидание всегда означает, что поток прекращает работу, и всякий раз, когда поток прекращает работу, вступает во владение какой-либо другой выполняемый поток.

Но если ваше намерение состоит в том, чтобы всегда дать другому потоку возможность работать в случае ошибки, независимо от того, select будет блокировать или нет (так как он не должен блокировать, вплоть до момента select вызывается, сокет может быть снова доступен для записи, и тогда он не будет блокироваться), тогда действительно может иметь смысл вызывать Thread.pass, Тем не менее, большинство программистов, вероятно, не назвали бы это в такой ситуации, как если бы select не будет блокироваться, обычно вы хотите, чтобы операция записи повторялась немедленно немедленно (в течение того же отрезка времени, если это возможно, а если нет, то ваш поток все равно пройдет).

Другие вопросы по тегам