Почему мне не разрешено нарушать обещание?

Дается следующее простое Обещание, и мне не разрешается его нарушать.

my $my_promise = start {
    loop {}   # or sleep x;
    
    'promise response'
}

say 'status : ', $my_promise.status;      # status : Planned

$my_promise.break('promise broke');       # Access denied to keep/break this Promise; already vowed
                                          # in block <unit> at xxx line xxx

Это почему?


person jakar    schedule 05.10.2020    source источник
comment
Семантически это было бы не очень хорошее имя, если бы его можно было сломать.   -  person TylerH    schedule 30.10.2020


Ответы (2)


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

Чего вы пытаетесь достичь, нарушая обещание, которое вы показали? Чтобы остановить работу, выполняемую внутри блока start? Нарушение обещания этого не сделает. И механизм vow был явно добавлен, чтобы вы не думали, что он может каким-то образом остановить работу внутри блока start.

Если вы хотите, чтобы работа внутри блока start была прерываемой, вам нужно будет добавить какой-то семафор, который регулярно проверяется, например:

my int $running = 1;
my $my_promise = start {
    while $running {
        # do stuff
    }
    $running
}

# do other stuff
$running = 0;
await $my_promise;

Надеюсь, это имело смысл.

person Elizabeth Mattijsen    schedule 05.10.2020

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

Обычное неправильное использование обещаний происходит из-за тайм-аута.

await Promise.anyof(
    start { sleep 4; say "finished"; },
    Promise.in( 1 )
);
say "moving on...";
sleep;

Эта будет печать завершена. И когда пользователь понимает, что следующий логический шаг для него - попытаться убить устаревший Promise. Хотя единственный правильный способ решить эту проблему - сообщить Promise, что его работа больше не нужна. Например, периодически проверяя некоторую общую переменную.

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

  • Вы можете скрипеть зубами и терпеливо ждать, пока Promise закончит. Например, если вам действительно нужно отключить базу данных в основном потоке.
  • Или вы можете сразу же перейти к следующему шагу и позволить заброшенному обещанию закончиться самостоятельно, так и не получив его результата. В этом случае вы должны контролировать, сколько из этих обещаний может складываться в фоновом режиме, используя семафор или выполняя их на выделенном ThreadPoolScheduler.
person Pawel Pabian bbkr    schedule 09.10.2020