raku Вызов одной и той же функции в потоках с разными параметрами - PullRequest
3 голосов
/ 25 апреля 2020

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

sub add ($a, $b) { $a + $b };
for 1..100 { start { sleep 1.rand; say "I am $_, {add($_, 1000)}"; } };

1 Ответ

4 голосов
/ 25 апреля 2020

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

Существует Одно исключение , о котором я могу подумать: использование переменной state внутри такой функции. Существует известное условие гонки при инициализации переменной состояния, и обновления в форме $foo++, скорее всего, будут пропускать приращения при одновременном запуске из нескольких потоков. Например:

my int $a;
await (^10).map: { start { $a++ for ^100000 } }
say $a;  # 893127

Ака, а не 1000000, который вы ожидаете. К счастью, для обработки этого случая у нас есть атомы c целых чисел:

my atomicint $a;
await (^10).map: { start { $a⚛++ for ^100000 } }
say $a;  # 1000000

Но это просто хвастовство, а не прямой ответ на ваш вопрос: -)

Если у вас есть фрагмент кода, который вы хотите убедиться, что одновременно выполняется только один поток, вы можете использовать Lock и protect метод для этого;

my $lock = Lock.new;  # usually in the mainline of a program
# ... code
$lock.protect: {
    # code executed by only 1 thread at a time
}

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

...