ithreads 可以与 Moose 惰性属性一起使用吗?

发布于 2024-12-29 18:34:43 字数 1161 浏览 3 评论 0原文

对于以下程序,我收到此错误消息:

线程 2 异常终止:共享标量的值无效 reader Foo::bar(定义于...第9行)第10行。

该程序由一个管道组成,其中第一个线程创建一些基于Moose的对象并将它们放入队列中,然后在第二个线程中拾取这些对象。问题似乎是该属性是惰性的,因为如果我删除惰性设置,错误就会消失。

package Foo;
use Moose;

has 'bar' => (
    is      => 'ro',
    isa     => 'HashRef', # the error doesn't happen with simpler datatypes
    lazy    => 1, # this line causes the error
    default => sub { return { map {$_ => $_} (1 .. 10) } },
);

package main;

use threads;
use Thread::Queue;

my $threadq = Thread::Queue->new;

sub create {
    # $_ doesn't seem to be thread-safe
    # this resolved another problem I had with a custom Moose type constraint 
    # where the 'where' clause used $_
    local $_;

    $threadq->enqueue( Foo->new ) foreach 1 .. 5;
    $threadq->enqueue( undef );
    return;
}

sub process {
    local $_;
    while (my $f = $threadq->dequeue) {
        print keys %{$f->bar}, "\n";
    }
    return;
}

threads->create( \&create )->join;
threads->create( \&process )->join;

任何人都可以阐明这个问题吗? Moose 本身是线程安全的吗(我在文档中找不到太多相关内容)?

For the below program I'm getting this error message:

Thread 2 terminated abnormally: Invalid value for shared scalar at
reader Foo::bar (defined at ... line 9) line 10.

The program consists of a pipeline where the first thread creates some Moose-based objects and puts them in the queue, which are then picked up in the second thread. The problem seems to be that the attribute is lazy because the error disappears if I remove the lazy setting.

package Foo;
use Moose;

has 'bar' => (
    is      => 'ro',
    isa     => 'HashRef', # the error doesn't happen with simpler datatypes
    lazy    => 1, # this line causes the error
    default => sub { return { map {$_ => $_} (1 .. 10) } },
);

package main;

use threads;
use Thread::Queue;

my $threadq = Thread::Queue->new;

sub create {
    # $_ doesn't seem to be thread-safe
    # this resolved another problem I had with a custom Moose type constraint 
    # where the 'where' clause used $_
    local $_;

    $threadq->enqueue( Foo->new ) foreach 1 .. 5;
    $threadq->enqueue( undef );
    return;
}

sub process {
    local $_;
    while (my $f = $threadq->dequeue) {
        print keys %{$f->bar}, "\n";
    }
    return;
}

threads->create( \&create )->join;
threads->create( \&process )->join;

Can anyone shed some light on this problem? Is Moose itself thread-safe (I couldn't find much in the documentation about this)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

給妳壹絲溫柔 2025-01-05 18:34:43

Thread::Queue 将对象中的所有哈希值和数组替换为具有相同内容的共享哈希值和数组,并且递归地执行此操作。

同时,你正在尝试改变对象。是的,这不会有好结果。 (并不是因为 Moose、Thread::Queue 或线程中的任何错误。)

解决方案是以序列化形式传递对象。您可以自己处理序列化和反序列化,也可以使用 Thread::Queue: :Any 隐式完成它。

use threads;
use Thread::Queue::Any;

my $threadq = Thread::Queue::Any->new;

sub create {
    $threadq->enqueue( Foo->new ) for 1 .. 5;
    $threadq->enqueue( );
}

sub process {
    while ( my ($f) = $threadq->dequeue ) {
       print sort keys %{$f->bar};
       print "\n";
    }
}

请注意,enqueuedequeue 的使用存在细微但重要的差异。最重要的是,使用 T::Q::A 时,必须在列表上下文中调用 dequeue。这是因为 enqueue 的参数列表作为一条消息传递,而 dequeue 返回该参数列表。

Thread::Queue replaces all the hashes and arrays in your object with shared hashes and arrays with the same content, and does so recursively.

At the same time, you are attempting to change the object. Yeah, that's not gonna end well. (And not because of any bug in Moose, Thread::Queue or threads.)

A solution is to pass around the object in a serialised form. You could handle serialisation and deserialisation yourself, or you could use Thread::Queue::Any to have it done implicitly.

use threads;
use Thread::Queue::Any;

my $threadq = Thread::Queue::Any->new;

sub create {
    $threadq->enqueue( Foo->new ) for 1 .. 5;
    $threadq->enqueue( );
}

sub process {
    while ( my ($f) = $threadq->dequeue ) {
       print sort keys %{$f->bar};
       print "\n";
    }
}

Note there are subtle but important differences in the usage of enqueue and dequeue. Most importantly, dequeue must be called in list context when using T::Q::A. This is because enqueue's argument list is passed as one message, and dequeue returns that argument list.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文