Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 将ithreads与Memoize一起使用时出错_Multithreading_Perl - Fatal编程技术网

Multithreading 将ithreads与Memoize一起使用时出错

Multithreading 将ithreads与Memoize一起使用时出错,multithreading,perl,Multithreading,Perl,我刚刚将线程引入了一个Perl程序,其中一个模块正在使用它。 我收到以下错误消息: 线程1异常终止:在禁止的标量上下文中调用匿名函数;断层 如果我同时拥有线程和Memoize,则会发生错误,但如果我去掉其中一个元素,错误就会消失。但问题并不是因为Memoize不是线程安全的——在我的代码中,所有的Memoize都发生在同一个线程中 这是Memoize的错误吗?我有办法解决这个问题吗?否则我就要扔掉备忘录了 下面是一些用于隔离问题的示例代码: use strict; use warnings; u

我刚刚将线程引入了一个Perl程序,其中一个模块正在使用它。 我收到以下错误消息:

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

如果我同时拥有线程和Memoize,则会发生错误,但如果我去掉其中一个元素,错误就会消失。但问题并不是因为Memoize不是线程安全的——在我的代码中,所有的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;

Memoize应在线程下工作,尽管速度稍慢:

“goto&f在线程化Perl下的工作方式存在一些问题,可能是因为@_的词法范围。这是 直到它被解析,记忆函数将看到一个轻微的错误 不同的调用者()将在线程上执行稍微慢一点 perls比无线程的perls更重要。”


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

问题在于,当函数被克隆到新线程中时,它的地址会发生变化。(在
invoke\u-foo
中添加
print(\&foo,“\n”);
)。这是备忘录中的一个错误

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


顺便说一下,每个线程都有自己的缓存。这也可能被认为是一个bug。

如前所述,
Memoize
不支持线程。如果你想要每个线程的记忆,ikegami的重组将很有效。相反,如果您想要全局备忘,则可以使用以下内容替换
Memoize

use strict;
use warnings;
use 5.010;
use threads;
use threads::shared;

sub memoize_shared {
    my $name = shift;
    my $glob = do {
        no strict 'refs';
        \*{(caller)."::$name"}
    };
    my $code = \&$glob;
    my $sep  = $;;
    my (%scalar, %list) :shared;

    no warnings 'redefine';
    *$glob = sub {
        my $arg = join $sep => @_;
        if (wantarray) {
            @{$list{$arg} ||= sub {\@_}->(&$code)}
        }
        else {
            exists $scalar{$arg}
                 ? $scalar{$arg}
                 :($scalar{$arg} = &$code)
        }
    }
}
使用它:

sub foo {
    my $x = shift;
    say "foo called with '$x'";
    "foo($x)"
}

memoize_shared 'foo';

for my $t (1 .. 4) {
    threads->create(sub {
        my $x = foo 'bar';
        say "thread $t got $x"
    })->join
}
其中打印:

foo called with 'bar' thread 1 got foo(bar) thread 2 got foo(bar) thread 3 got foo(bar) thread 4 got foo(bar)
将memoize构建到子例程中确实会使它变得更复杂,但它比使用诸如
memoize
之类的包装函数要快。它可以让您精确控制如何记忆子例程,包括使用
threads::shared
缓存。

您运行的是什么版本的perl?(询问原因)我正在使用带有Memoize 1.02的草莓Perl 5.12.3。我无法复制那个bug。我5年前才看到这个(仍然没有解决) foo called with 'bar' thread 1 got foo(bar) thread 2 got foo(bar) thread 3 got foo(bar) thread 4 got foo(bar)
{my %cache :shared;
sub foo {
    my $x = shift;
    if (exists $cache{$x}) {$cache{$x}}
    else {
        say "foo called with '$x'";
        $cache{$x} = "foo($x)"
    }
}}