Что "select((select(s),$|=1)[0])" делает в Perl?

Я видел какой-то ужасающий код, написанный на Perl, но я не могу понять, как это сделать:

select((select(s),$|=1)[0])

Это в каком-то сетевом коде, который мы используем для связи с сервером, и я предполагаю, что это как-то связано с буферизацией (так как она устанавливает $|).

Но я не могу понять, почему есть несколько select вызовы или ссылка на массив. Может кто-нибудь мне помочь?

7 ответов

Решение

Это неприятная маленькая идиома для установки автозаполнения на файловом дескрипторе, отличном от STDOUT.

select() берет предоставленный файловый дескриптор и (в основном) заменяет STDOUT этим, и он возвращает старый файловый дескриптор, когда это сделано.

Так (select($s),$|=1) перенаправляет файловый дескриптор (помните select возвращает старую) и устанавливает автозапуск ($| = 1). Это делает это в списке ((...)[0]) и возвращает первое значение (которое является результатом select вызов - исходный STDOUT), а затем передает это обратно в другой select восстановить исходный дескриптор файла STDOUT. Уф.

Но теперь вы понимаете это (ну, может быть;)), сделайте это вместо этого:

use IO::Handle;
$fh->autoflush;

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

Первый бит тогда:

( select(s), $|=1 )

Этот список содержит два элемента, которые являются результатом двух операций: один для выбора s дескриптор файла по умолчанию, а затем установить $| к истинному значению. $| является одной из переменных дескриптора файла, которые применяются только к текущему выбранному дескриптору файла (см. Общие сведения о глобальных переменных в The Effective Perler). В конце концов, у вас есть список из двух элементов: предыдущий дескриптор файла по умолчанию (результат select) и 1.

Следующая часть - это буквальный фрагмент списка для извлечения элемента в индексе 0:

( PREVIOUS_DEFAULT, 1 )[0]

Результатом этого является единственный элемент, который является предыдущим дескриптором файла по умолчанию.

Следующая часть берет результат среза и использует его в качестве аргумента для другого вызова select

 select( PREVIOUS_DEFAULT );

Итак, по сути, вы установили $| на файловом дескрипторе и в итоге вернулся туда, где вы начали с файловым дескриптором по умолчанию.

select($fh)

Выберите новый дескриптор файла по умолчанию. См. http://perldoc.perl.org/functions/select.html

(select($fh), $|=1)

Включите автозапуск. См. http://perldoc.perl.org/perlvar.html

(select($fh), $|=1)[0]

Вернуть первое значение этого кортежа.

select((select($fh), $|=1)[0])

select это, то есть восстановить старый дескриптор файла по умолчанию.


Эквивалентно

$oldfh = select($fh);
$| = 1;
select($oldfh);

что значит

use IO::Handle;
$fh->autoflush(1);

как показано на странице perldoc.

В другом месте я однажды предложил, чтобы более понятная версия была такой:

for ( select $fh ) { $| = 1; select $_ }

Это сохраняет единственное преимущество компактной идиомы в том, что не нужно объявлять переменные в окружающей области видимости.

Или если вам не нравится $_, вы можете написать это так:

for my $prevfh ( select $fh ) { $| = 1; select $prevfh }

Объем $prevfh ограничивается for блок. (Но если вы напишите на Perl, у вас действительно не будет повода быть пугливым $_.)

Это слишком умный код для включения очистки буфера на дескрипторе s и затем повторно выбирая текущий дескриптор.

Увидеть perldoc -f select для большего.

Это чрезмерная оптимизация, чтобы пропустить загрузку IO::Handle.

use IO::Handle;
$fh->autoflush(1);

гораздо более читабельным.

Пожалуйста, проверьте perldoc -f выберите. Для смысла $|Пожалуйста, проверьте Perldoc Perlvar

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