[Cascavel-pm] threads e uso de CPU

Alceu R. de Freitas Jr. glasswalk3r em yahoo.com.br
Quarta Dezembro 9 15:29:22 PST 2009


Olá monges,

Estou utilizando o código abaixo para rodar tarefas em paralelo:

<code>
use warnings;
use strict;
use DBI;
use Text::LevenshteinXS qw(distance);
use Benchmark qw(timediff timestr);
use Term::ProgressBar;
use threads;
use threads::shared;

my $t0 = Benchmark->new();

my %contacts : shared;
my @con_list : shared;
my $minimum_score : shared = 85;
my $maximum_threads = 6;
my @threads;

get_db_data();

my @control = @con_list;
my $item;

print 'Starting processing data with maximum of ', $maximum_threads,  ' threads', "\n";

my $progress = Term::ProgressBar->new(
    { name => 'Find Duplicated', count => scalar(@control) } );
my $total_processed = 0;

while (@control) {

    $maximum_threads = scalar(@control)
      if ( scalar(@control) < $maximum_threads );

    my $i;

    for ( $i = 1 ; $i <= $maximum_threads ; $i++ ) {

        $threads[$i] = create_thread( "result_$i.txt", ( shift(@control) ) );

    }

    for ( $i = 1 ; $i <= $maximum_threads ; $i++ ) {

        my ($found) = $threads[$i]->join();
		#print "thread $i found $found" if ($found > 0);

    }

    $total_processed += $i;

    $progress->update($total_processed);

}

$progress->update($total_processed);

my $t1 = Benchmark->new();
my $td = timediff( $t1, $t0 );
print 'the code took:', timestr($td), "\n";

sub create_thread {

    my $file    = shift;
    my $contact = shift;

    my $trh1 = threads->new( \&validate_contact, $file, $contact );

}

sub validate_contact {

    my $file = shift;
    my $item = shift;

    my $counter = 0;

    open( OUT, '>>', $file ) or die "Cannot create $file: $!\n";

    my $source_name = $contacts{$item}->[0] . ' ' . $contacts{$item}->[1];

    foreach my $contact (@con_list) {

        #PERSON_UID is the same
        next if $item eq $contact;

        my $dest_name =
          $contacts{$contact}->[0] . ' ' . $contacts{$contact}->[1];
        my $dest_len = length($dest_name);

        $dest_len = 1 unless ( $dest_len > 0 );

        my $distance = distance( $source_name, $dest_name );

        my $score = 100 - ( ( $distance * 100 ) / $dest_len );

        # how much equal is the current row with the original one
        if ( $score >= $minimum_score ) {

            # source FST_NAME|LAST_NAME|CON_CD|PERSON_UID
            print OUT $contacts{$item}->[0], '|', $contacts{$item}->[1],
              '|',
              $contacts{$item}->[2], '|', $item, '|';

            # dest FST_NAME|LAST_NAME|CON_CD|PERSON_UID|SCORE
            print OUT $contacts{$contact}->[0], '|',
              $contacts{$contact}->[1],
              '|', $contacts{$contact}->[2], '|', $contact, '|', $score,
              "\n";

            $counter++;

        }

    }

    close(OUT);

    return $counter;

}

sub get_db_data {

	print 'Fetching contacts from database... ';

    my $user     = 'TESTE';
    my $password = 'TESTE';
    my $DSN      = 'TESTE';

    my $dbh =
      DBI->connect( 'dbi:ODBC:' . $DSN, $user, $password, { RaiseError => 1 } )
      or die "Database connection not made: $DBI::errstr";

    my $query = q(
SELECT FST_NAME, LAST_NAME, PERSON_UID, CON_CD FROM CONTACT
ORDER BY FST_NAME, LAST_NAME
);

    my $sth = $dbh->prepare($query);
    $sth->execute();

    while ( my $data = $sth->fetchrow_hashref() ) {

        # avoid warnings
        $data->{FST_NAME}  = '' unless ( defined( $data->{FST_NAME} ) );
        $data->{LAST_NAME} = '' unless ( defined( $data->{LAST_NAME} ) );
        $data->{CON_CD}    = '' unless ( defined( $data->{CON_CD} ) );

        my @temp : shared =
          ( $data->{FST_NAME}, $data->{LAST_NAME}, $data->{CON_CD} );

        $contacts{ $data->{PERSON_UID} } = \@temp;

        push( @con_list, $data->{PERSON_UID} );

    }

    $sth->finish();

    $dbh->disconnect() or warn $dbh->errstr;

	print "OK\n";

}
</code>

O código executa normalmente, exceto pelo fato que mais lento do que eu gostaria. Otimizações à parte (como remover registros do hash depois de processados, algo que ainda não fiz) eu percebi que o computador aonde estou rodando isso (Intel Core2 DUO) não usa toda a capacidade de CPU (memória não é gargalo aqui). Ela fica entre 60 e 70% de uso. Eu gostaria que ficasse em algo como 90%, mas mesmo aumentando o número de threads simultâneas esse percentual não muda (e suspeito que o programa não vai rodar mais rápido por isso). Esse é um comportamento normal de se trabalhar com threads? É a primeira vez que uso isso com Perl.

Apesar de ler sobre recomendações de não usar threads com Perl, estou em um ambiente Microsoft e gostaria de alternativas simples de compartilhar dados em memória com execuções paralelas. Fico aberto à sugestões.

Abraços,

Alceu Rodrigues de Freitas Junior
--------------------------------------
glasswalk3r em yahoo.com.br
---
A well-used door needs no oil on its hinges.
A swift-flowing stream does not grow stagnant.
Neither sound nor thoughts can travel through a vacuum.
Software rots if not used.
These are great mysteries -- The Tao Of Programming, 5.1


      ____________________________________________________________________________________
Veja quais são os assuntos do momento no Yahoo! +Buscados
http://br.maisbuscados.yahoo.com


Mais detalhes sobre a lista de discussão Cascavel-pm