Perl foreach循环改多线程报Invalid value for shared scalar错误如何解决
问题原因
- 你调用
share()时传入的$a1/$b1等变量已经被赋值为普通非共享哈希引用,threads::shared不支持直接将已存在的非共享变量转为共享变量,这是触发Invalid value for shared scalar报错的直接原因 - 即使提前声明共享变量,嵌套的哈希结构也需要逐层设置为共享,否则嵌套赋值时仍会触发同类错误,且多线程写共享哈希需要加锁,反而可能抵消多线程的性能收益
- 原有代码存在语法错误:线程join的逻辑中
thr->join()缺少变量标识符,正确写法为$thr->join()
最优解决方案(无共享变量、不改动原有前后逻辑)
因为你明确提到各次迭代相互独立、填充字典的key互不重叠,完全可以让每个线程仅计算自己负责的部分结果,主线程等所有线程执行完成后再合并结果到原字典中,全程不需要处理共享变量,也不会影响循环前后的原有代码逻辑。
示例代码如下:
my $a1 = {}; my $b1 = {}; my $c1 = {}; my $d1 = {}; # 大量使用$a1和$b1的原有代码,完全不需要改动 my @threads; foreach my $Inst ( sort keys %{ $a1->{ports} }) { push( @threads, threads->create('some_func', $Inst)); } # 每个线程返回自己负责的key对应的结果,结构示例: # return ($inst_key, {a1_part => {}, b1_part => {}, c1_part => {}, d1_part => {}}) for my $thr (@threads) { my ($inst, $res) = $thr->join(); # 合并结果到原字典,因为key不重叠,不会有冲突 $a1->{$inst} = $res->{a1_part}; $b1->{$inst} = $res->{b1_part}; $c1->{$inst} = $res->{c1_part}; $d1->{$inst} = $res->{d1_part}; } # 其余所有原有代码,完全不需要改动
备选方案(坚持使用共享变量的修改方式)
如果一定要用共享变量实现,需要调整共享变量的声明时机,并且逐层处理嵌套结构:
- 在给字典赋值之前就声明为共享变量,原有操作共享字典的代码不需要调整(
threads::shared的共享哈希操作接口和普通哈希完全兼容) - 所有嵌套的哈希/数组结构也需要用
shared_clone包裹后再赋值,避免赋值非共享结构报错
示例代码如下:
use threads::shared; # 提前声明共享变量 my $a1 :shared = {}; my $b1 :shared = {}; my $c1 :shared = {}; my $d1 :shared = {}; # 大量使用$a1和$b1的代码,嵌套结构赋值时需要用shared_clone包裹非共享结构 # 示例:赋值$a1->{ports}的时候要写成 $a1->{ports} = shared_clone({...}); my @threads; foreach my $Inst ( sort keys %{ $a1->{ports} }) { push( @threads, threads->create('some_func', $Inst, $a1, $b1, $c1, $d1, $e ...)); } for my $thr (@threads) { $thr->join(); } # 其余所有代码
内容的提问来源于stack exchange,提问作者urie
相关产品推荐
相关产品推荐

