0

Hi I'm trying to add multiple keys/values into a hash. Basically file names and their data. Each of the json file's content have hash and array referencing. The hash that contains the file names and data will be handled else where.

This is my code:

 sub getDecode {
    my $self = shift;
    my @arrUrls = ('http://domain.com/test.json', 'http://domain.com/test_two.json', 'http://domain.com/test3.json');

    my $resQueue = Thread::Queue->new();
    my $intThreads = 10;
    my @arrThreads = ();
    my %arrInfo = ();

    foreach my $strUrl (@arrUrls) {
          for (1..$intThreads) {
              push (@arrThreads, threads->create(sub {
                          while (my $resTask = $resQueue->dequeue) {
                                      my $resData = get($strUrl);
                                      my $strName = basename($strUrl, '.json');
                                      my $arrData = decode_json($resData);
                                      $arrInfo{$strName} = $arrData;
                          }
              }));
          }
   }

   $resQueue->enqueue(@arrUrls);
   $resQueue->enqueue(undef) for 1..$intThreads;
   $_->join for @arrThreads;

  return %arrInfo;       
  }

When I try data dumping on %arrInfo no output is given. Please help!

1 Answer 1

1

You're multithreading and not sharing the variable. When a thread spawns, the existing variable-space is cloned - so each thread has it's own local copy of %arrInfo which is discarded when it exits.

You need to:

use threads::shared;
my %arrInfo : shared;

You're also doing something a bit odd with your thread spawn loop - you're spawning 10 threads x 3 URLs - for 30 threads, but only queuing 3 URLs to process. But then you're also not actually using $resTask at all, which doesn't make a lot of sense.

So I'm prepared to bet your code hangs at the end, because you're trying to join some threads that aren't complete.

You might find $resQueue -> end() is more suitable than queuing up undef.

Example using a shared hash:

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

use Data::Dumper;

my %test_hash : shared;
my %second_hash;

$test_hash{'from_parent'}       = 1;
$second_hash{'from_parent_too'} = 1;

threads->create(
    sub {
        $test_hash{'from_first'}       = 2;
        $second_hash{'from_first_too'} = 2;
    }
);
threads->create(
    sub {
        $test_hash{'from_second'}       = 3;
        $second_hash{'from_second_too'} = 3;
    }
);

foreach my $thr ( threads->list() ) { $thr->join }

print Dumper \%test_hash;
print Dumper \%second_hash;

For a 'worker threads' style approach, I'd offer: Perl daemonize with child daemons

Sign up to request clarification or add additional context in comments.

6 Comments

There's actually more urls but I removed them. Thank you though :)
You're still spawning 10 threads per URL, and it looks like 9 of those will be redundant.
Just a question, it keeps saying "invalid value for shared scalar"
Not sure why. My test case works ok. Which line gives that error? (And are you still assigning an empty array to %arrInfo because that's redundant)
Edited answer with example
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.