печатать каждую секунду, а также спать 10 секунд, очень 5 секунд, используя реагировать ... когда-нибудь в Perl 6? - PullRequest
0 голосов
/ 16 ноября 2018

Я хочу печатать текущее время каждую секунду, а также хочу спать 10 секунд, очень 5 секунд:

react {
    whenever Supply.interval(1) {
        say DateTime.now.posix;
    }

    whenever Supply.interval(5) {
        sleep 10;
        say 'Sleep Done';
    }

    whenever signal(SIGINT) {
        say "Done.";
        done;
    }
}

вывод не то, что я хотел:

1542371045
Sleep Done
1542371055
Sleep Done
1542371065
Sleep Done
1542371075
Done.
...

что я хочу это:

1542371045
1542371046
1542371047
1542371048
1542371049 
Sleep Done
1542371059
1542371060
1542371061  
1542371062 
1542371063         
Sleep Done
Done.

Не знаю много о Promise, Supply ... о Perl 6, возможно ли это?

Ответы [ 5 ]

0 голосов
/ 16 ноября 2018

В зависимости от того, что еще было нужно, я, вероятно, напишу это примерно так:

react {
    sub sequence() {
        whenever Supply.interval(1).head(5) {
            say DateTime.now.posix;
            LAST whenever Promise.in(10) {
                say "Sleep done";
                sequence();
            }
        }
    }
    sequence();
}   

Что дает вывод, как это:

1542395158
1542395159
1542395160
1542395161
1542395162
Sleep done
1542395172
1542395173
1542395174
1542395175
1542395176
Sleep done
1542395186
1542395187
1542395188
...

Это гарантирует, что вы получите 5 тиков между 10-секундными паузами; выполнение этого с двумя отдельными интервальными поставками - как во многих решениях здесь - не даст никаких строгих гарантий этого, и может время от времени пропускать галочку. (Тот, который не делает, - симпатичный с rotor, который является хорошей ставкой, если вам не нужно фактически печатать вещь "Sleep Done"). Он также свободен от состояния (переменных) и условий, что довольно приятно.

Хотя это выглядит так, как будто оно может быть рекурсивным, поскольку whenever является асинхронной циклической конструкцией, фактически она вообще не будет создавать стек вызовов.

Он также полностью построен из асинхронных конструкций, и поэтому в Perl 6.d не будет - если react запущен в пуле потоков - когда-либо блокировать реальный поток ОС. Таким образом, вы можете иметь тысячи таких активных. В отличие от этого, sleep будет блокировать реальный поток, что, как и ожидалось бы от sleep, традиционно ожидалось, но не очень подходит, если в противном случае иметь дело с асинхронными конструкциями.

0 голосов
/ 16 ноября 2018

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

Вы также должны попытаться запустить код в whenever как можно быстрее.
(Представьте, что это обработчик прерываний процессора.)
Из этого правила могут быть некоторые исключения, особенно для supply блоков.

Используя предоставленную вами структуру, это один из способов достижения желаемого:

 react {
    # Are we ignoring the interval(1) values?
    my Bool:D $ignore = False;

    # The sleeping status of interval(5).
    my Promise:D $sleep .= kept;

    whenever Supply.interval(1) {
        # Skip if it is supposed to be blocked.
        next if $ignore;

        say DateTime.now.posix;
    }

    # First one runs immediately, so skip it.
    whenever Supply.interval(5).skip {
        # Don't run while the “sleep” is pending.
        next unless $sleep.status; # Planned

        if $ignore {
            $ignore = False;
            say 'Sleep Done';
        } else {
            $ignore = True;
            # Must be less than the multiple of 5 we want
            # otherwise there may be a race condition.
            $sleep = Promise.in(9);
        }
    }

    whenever signal(SIGINT) {
        say "Done.";
        done;
    }
}

Это не очень понятно.
Как насчет того, чтобы просто использовать .rotor, чтобы пропустить каждый третий интервал из 5?

react {
    my Bool:D $ignore = True;

    # Note that first one runs immediately. (no .skip)
    # We also want it to always be a few milliseconds before
    # the other Supply, so we put it first.
    # (Should have done that with the previous example as well.)
    whenever Supply.interval(5).rotor(1, 1 => 1) {
        $ignore = !$ignore;
    }

    whenever Supply.interval(1) {
        next if $ignore;

        say DateTime.now.posix;
    }

    whenever signal(SIGINT) {
        say "Done.";
        done;
    }
}

Пока мы занимаемся этим, почему бы не использовать .rotor в .interval(1) Supply?

react {
    whenever Supply.interval(1).rotor(1 xx 4, 1 => 10) {
        say DateTime.now.posix;
    }

    whenever signal(SIGINT) {
        say "Done.";
        done;
    }
}

Обратите внимание, что мы не можем просто использовать 5 => 10, потому что это объединяет их, и мы хотим, чтобы они запускались по отдельности.


Обратите внимание, что .grep также работает с припасами, поэтому мы могли бы использовать его для проверки значения $ignored.

react {
    my Bool:D $ignore = True;

    whenever Supply.interval(5).rotor(1, 1 => 1) {
        $ignore = !$ignore;
    }

    whenever Supply.interval(1).grep({ !$ignore }) {
        say DateTime.now.posix;
    }

    whenever signal(SIGINT) {
        say "Done.";
        done;
    }
}
0 голосов
/ 16 ноября 2018

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

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

react { 
    whenever Supply.interval(1) { 
        state $slept = False;  
        state $count = 0;
        if $count >= 0 { 
            if $slept { 
                say "Sleep Done"; 
                $slept = False 
            } 
            say DateTime.now.posix; 
        } 
        $count++; 
        if ( $count == 5 ) { 
            $count = -9; 
            $slept = True
        }
    }
    whenever signal(SIGINT) {
        say "Done.";
        done;
    }
}

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

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

0 голосов
/ 16 ноября 2018

Поскольку только one whenever будет выполняться в любое время, sleep в нем прекратит всю обработку вещей, на которые нужно реагировать.Самый простой способ добиться того, чего вы хотите, это выполнить sleep как асинхронную работу, поместив код этого whenever в блок start.

react {
    whenever Supply.interval(1) {
        say DateTime.now.posix;
    }

    whenever Supply.interval(5) {
        start {
            sleep 10;
            say 'Sleep Done';
        }
    }

    whenever signal(SIGINT) {
        say "Done.";
        done;
    }
}

Это дает желаемый результатнасколько я вижу.

0 голосов
/ 16 ноября 2018

Может быть, это может работать:

loop {
    react {
        whenever Supply.interval(1) {
            say DateTime.now.posix;
        }

        whenever Promise.in(5) {
            done;
        }

        whenever signal(SIGINT) {
            say "Done.";
            done;
        }
    }
    sleep 10;
}

Вывод:

1542347961
1542347962
1542347963
1542347964
1542347965
1542347976 # <- 10s
1542347977
1542347978
1542347979
1542347980
1542347991 # <- 10s
...