将ithreads与Memoize一起使用时出错

ste*_*enl 5 perl multithreading

我刚刚向Perl程序引入了线程,其中一个模块使用了Memoize.我收到此错误消息:

线程1异常终止:在禁止标量上下文中调用匿名函数; 断层

如果我同时拥有线程和Memoize,则会发生错误,但如果我删除其中一个元素,则会消失.但问题不在于Memoize不是线程安全的 - 在我的代码中,所有的memoization都发生在同一个线程中.

这是Memoize的错误吗?有没有办法可以解决这个问题?否则我将摆脱Memoize.

以下是一些示例代码来隔离问题:

use strict;
use warnings;
use threads;
use Thread::Semaphore;
use Memoize;

my $semaphore = Thread::Semaphore->new;

memoize('foo');
sub foo {
    return shift;
}

sub invoke_foo {
    $semaphore->down; # ensure memoization is thread-safe
    my $result = foo(@_);
    $semaphore->up;

    return $result;
}

my @threads;
foreach (1 .. 5) {
    my $t = threads->create( sub { invoke_foo($_) });
    push @threads, $t;
}
$_->join foreach @threads;
Run Code Online (Sandbox Code Playgroud)

ike*_*ami 4

Memoize 将每个记忆函数的缓存存储在一个哈希中(而不是使用闭包)。它使用函数的地址作为该哈希的索引。

问题在于,当函数被克隆到新线程中时,它的地址会发生变化。(加入print(\&foo, "\n");invoke_foo)。这是 Memoize 中的一个错误。

解决方法:从线程内加载记忆模块。以下模拟(相关方面):

use strict;
use warnings;
use threads;
use Memoize;

sub foo {
    return shift;
}

sub invoke_foo {
    return foo(@_);
}

my @threads;
foreach (1 .. 5) {
    my $t = threads->create( sub {
        memoize('foo');
        invoke_foo($_);
    });
    push @threads, $t;
}
$_->join foreach @threads;
Run Code Online (Sandbox Code Playgroud)

顺便说一句,每个线程都有自己的缓存。这也可以被视为一个错误。