Подтвердить что ты не робот

Неблокирующее/асинхронное выполнение в Perl

Есть ли способ реализовать неблокирующее/асинхронное выполнение (без fork() 'ing) в Perl?

Я был разработчиком Python на протяжении многих лет... У Python действительно отличная фреймворк "Twisted", который позволяет это сделать (используя DEFERREDs. Когда я побежал чтобы увидеть, есть ли что-нибудь в Perl, чтобы сделать то же самое, я наткнулся на инфраструктуру POE, которая казалась "близкой" к тому, что я искал. после того как я потратил некоторое время на чтение документации и "играю" с кодом, я выступил против "стены" - это следующее ограничение (из POE:: Session)

Обратные вызовы не являются превентивными. Пока вы работаете, никто не будет отправлен. Это называется совместной многозадачностью. Каждый сеанс должен взаимодействовать, возвращаясь к центральному диспетчерскому ядру.

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

Итак... есть ли какой-либо способ в Perl реализовать многозадачность (параллельное, неблокирующее, асинхронное выполнение кода) без fork() 'ing - похоже на DEFERREDs в Python?

4b9b3361

Ответ 1

Coro - это смесь между POE и потоками. От чтения документации CPAN, я думаю, что IO:: Async выполняет реальное асинхронное выполнение. threads - по крайней мере Padre IDE успешно использует их.

Ответ 2

Я не очень хорошо знаком с Twisted или POE, но базовое параллельное выполнение довольно просто с threads. Интерпретаторы, как правило, не скомпилированы с поддержкой потоковой передачи, поэтому вам нужно будет это проверить. Пакет forks - это замена для потоковой передачи (реализует полный API), но без использования процессов. Затем вы можете делать такие вещи:

my $thread = async {
    print "you can pass a block of code as an arg unlike Python :p";
    return some_func();
};
my $result = $thread->join();

Я определенно реализовал обратные вызовы из цикла событий в асинхронном процессе с использованием forks, и я не понимаю, почему он не будет работать с потоками.

Ответ 3

Twisted также использует совместную многозадачность, как POE и Coro.

Однако похоже, что Twisted Deferred использует (или может) использовать потоки. NB. См. Этот ответ из вопроса SO Twisted: неблокирующий код

Итак, вам нужно пойти по тому же маршруту с POE (хотя используя вилка, вероятно, предпочтительнее).

Таким образом, одно решение POE должно было бы использовать: POE::Wheel::Run - переносимый блок-код и программы в подпроцессах.

Для альтернатив POE посмотрите AnyEvent и Reflex.

Ответ 4

Я считаю, что вы используете select для такого рода вещей. Более похоже на forking, threading.

Ответ 5

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

Ответ 6

Никакой другой обратный вызов не может запускаться, пока другой уже запущен!

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

Вы не можете прерывать прерывание, если прерывание не было запрограммировано специально для его размещения.

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