зависит ли сигнал () в порядке реагирования блока? - PullRequest
8 голосов
/ 21 мая 2019

У меня есть небольшая программа, которая запускается до получения SIGINT или до получения двух строк (дважды нажмите enter) от stdin.Логика блока реакции:

react {
    whenever signal(SIGINT) {
        say "Got signal";
        exit;
    }
    whenever $*IN.lines.Supply {
        say "Got line";
        exit if $++ == 1 ;
    }
}

Программа выйдет на две введенные строки, как и ожидалось.

Однако CTRL-C ничего не сделает, если за ней не следует строка (ввод).

Если я переключаю порядок блоков всякий раз, программа прерывается SIGINT, но не выполняет сигнал всякий раз, когда блок

react {
    whenever $*IN.lines.Supply {
        say "Got line";
        exit if $++ == 1 ;
    }
    whenever signal(SIGINT) {
        say "Got signal";
        exit;
    }
}

Требуются ли какие-либо другие настройки перед использованиемсигнал саб?Является ли порядок блоков важными в реактивном блоке?

Обновление

Таким образом, кажется, что вызов lines () блокирует выполнение реактивного блока (спасибо @ Håkon).Я вроде понял.

При сравнении с похожей структурой кода для чтения сокетов я все же запутался.Наличие данных (или их отсутствие) не влияет на выполнение обработчика сигнала, и в этом примере он может очень просто читать строки:

my $listener=IO::Socket::Async.listen("0.0.0.0",4432);
react {
    whenever $listener {
        whenever $_.Supply.lines() {
            say "Got line";
        }
    }
    whenever signal(SIGINT) {
        say "Got signal";
        exit;
    }
}

#testing with:
#   curl http://localhost:4432

Почему это так отличается от моего исходного кода?

Ответы [ 2 ]

8 голосов
/ 22 мая 2019

Порядок не имеет значения , если источники данных действительно ведут себя асинхронно , что, к сожалению, здесь не так.Устройство Supply на Seq не вводит параллелизма и немедленно пытается создать значение для выброса на Supply, что в свою очередь блокирует чтение из $*IN.Таким образом, вторая подписка не имеет возможности быть настроенной;та же самая основная проблема вызывает другие наблюдаемые проблемы.

Решение состоит в том, чтобы заставить чтение происходить «в другом месте».Мы можем сделать это с Supply.from-list(...), плюс сказать, что мы действительно хотим использовать текущий планировщик, а не его значение по умолчанию CurrentThreadScheduler.Таким образом, это ведет себя так, как хотелось:

react {
    whenever Supply.from-list($*IN.lines, scheduler => $*SCHEDULER) {
        say "Got line";
        exit if $++ == 1 ;
    }
    whenever signal(SIGINT) {
        say "Got signal";
        exit;
    }
}

Вероятно, эта область будет несколько пересмотрена в будущих версиях Perl 6.Текущее поведение было благонамеренным;принцип разработки заключался в том, чтобы избежать неявного введения параллелизма, следуя общему принципу, что поставки являются инструментом для управления параллелизмом, который по своей природе существует, а не для его введения.Однако в действительности отсутствие параллелизма здесь, вероятно, споткнуло больше людей, чем помогло.(Кроме того, мы можем рассмотреть возможность предложить реальный неблокирующий файловый ввод / вывод, а не строить его из потоков файлового ввода / вывода +.)

3 голосов
/ 21 мая 2019

Вот вариант, который запускает обработчик сигнала (на основе этого ответа), но, к сожалению, автоматическая очистка $*IN, кажется, отключена:

my $lines = supply {
    whenever start $*IN.lines.Supply {
        whenever .lines { .emit }
    }
}.Channel;

react {
    whenever signal(SIGINT) {
        say "Got signal";
        exit;
    }
    whenever $lines {
        say "Got line: '{$_}'";
        exit if $++ == 1;
    }
}

Теперь у вас естьнажмите CTRL-D, чтобы напечатать строки, а затем напечатайте все строки, введенные в виде объединенной строки, и после этого $*IN закроется. Как включить автоматическую очистку для $*IN в этом случае?

...