• No results found

Getting Started with Multithreaded Perl

N/A
N/A
Protected

Academic year: 2021

Share "Getting Started with Multithreaded Perl"

Copied!
167
0
0

Loading.... (view fulltext now)

Full text

(1)

Getting Started with

Multithreaded Perl

Walt Mankowski ([email protected]) Drexel University

YAPC::EU 2009 5 August 2009

(2)
(3)
(4)
(5)

The number of transistors on a chip doubles about every

two years.

(6)
(7)
(8)
(9)
(10)

Why threads?

CPUs not getting any faster, but…

(11)

Why threads?

CPUs not getting any faster, but…

CPUs continue to get smaller and more numerous, so…

(12)

Why threads?

CPUs not getting any faster, but…

CPUs continue to get smaller and more numerous, so…

To run faster, need to use more than 1 CPU.

(13)
(14)
(15)

Parallel Processing

pthreads

(16)

Parallel Processing

pthreads

(17)

Parallel Processing

pthreads

MPI

(18)

Parallel Processing

pthreads

MPI

OpenMP Linda

(19)

Parallel Processing

pthreads MPI OpenMP Linda Java threads

(20)

Parallel Processing

pthreads MPI OpenMP Linda Java threads shell pipeline

(21)

Parallel Processing

pthreads MPI OpenMP Linda Java threads shell pipeline fork()

(22)

Parallel Processing

pthreads MPI OpenMP Linda Java threads shell pipeline fork() semaphores

(23)

Parallel Processing

pthreads MPI OpenMP Linda Java threads shell pipeline fork() semaphores shared memory

(24)

Parallel Processing

pthreads MPI OpenMP Linda Java threads shell pipeline fork() semaphores shared memory pipes

(25)

Parallel Processing

pthreads MPI OpenMP Linda Java threads shell pipeline fork() semaphores shared memory pipes sockets

(26)

Parallel Processing

pthreads MPI OpenMP Linda Java threads shell pipeline fork() semaphores shared memory pipes sockets etc…

(27)
(28)

Threads vs Processes

In general (not necessarily in Perl) …

(29)

Threads vs Processes

In general (not necessarily in Perl) …

(30)

Threads vs Processes

In general (not necessarily in Perl) …

threads lighter-weight than processes

(31)

Threads vs Processes

In general (not necessarily in Perl) …

threads lighter-weight than processes

faster to create, faster to switch

(32)

Threads vs Processes

In general (not necessarily in Perl) …

threads lighter-weight than processes

faster to create, faster to switch

easier to share data between threads

(33)

Threads vs Processes

In general (not necessarily in Perl) …

threads lighter-weight than processes

faster to create, faster to switch

easier to share data between threads

shared data in same memory location

(34)

Threads vs Processes

In general (not necessarily in Perl) …

threads lighter-weight than processes

faster to create, faster to switch

easier to share data between threads

shared data in same memory location

harder to debug threads

(35)
(36)

A Little History

(37)

A Little History

Threads.pm

(38)

A Little History

Threads.pm

• introduced in 5.005 • sucked

(39)

A Little History

Threads.pm

• introduced in 5.005 • sucked

(40)

A Little History

Threads.pm • introduced in 5.005 • sucked • deprecated • removed in 5.10

(41)
(42)

A Little History

(43)

A Little History

threads.pm

(44)

A Little History

threads.pm

• introduced in 5.8 • improved in 5.10

(45)

A Little History

threads.pm

• introduced in 5.8 • improved in 5.10

(46)

A Little History

threads.pm

• introduced in 5.8 • improved in 5.10

• "interpreter threads" (ithreads)

• separate Perl interpreter for each threads

(47)
(48)

#!/usr/bin/perl -w use strict; use threads; my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; sub tsub {

print "I like pie\n"; }

(49)

#!/usr/bin/perl -w use strict; use threads; my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; sub tsub {

print "I like pie\n"; }

(50)

#!/usr/bin/perl -w use strict; use threads; my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; sub tsub {

print "I like pie\n"; }

(51)

#!/usr/bin/perl -w use strict;

use threads; # as early as possible

my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join;

$t2->join; sub tsub {

print "I like pie\n"; }

(52)

#!/usr/bin/perl -w use strict; use threads; my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; sub tsub {

print "I like pie\n"; }

(53)

#!/usr/bin/perl -w use strict; use threads; my $t1 = threads->create(\&tsub); my $t2 = threads->create(\&tsub); $t1->join; $t2->join; sub tsub {

print "I like pie\n"; }

(54)

#!/usr/bin/perl -w use strict; use threads; my $t1 = threads->new("tsub"); my $t2 = threads->new("tsub"); $t1->join; $t2->join; sub tsub {

print "I like pie\n"; }

(55)

#!/usr/bin/perl -w use strict; use threads; my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; sub tsub {

print "I like pie\n"; }

(56)

#!/usr/bin/perl -w use strict; use threads; my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->detach; $t2->detach; sub tsub {

print "I like pie\n"; }

(57)

#!/usr/bin/perl -w use strict; use threads; threads->new(\&tsub)->detach; threads->new(\&tsub)->detach; sub tsub {

print "I like pie\n"; }

(58)

#!/usr/bin/perl -w use strict; use threads; my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; sub tsub {

print "I like pie\n"; }

(59)
(60)

Anonymous subs

my $t1 = threads->new(

sub {print "I like pie\n";} );

(61)

Anonymous subs

my $t1 = threads->new(

sub {print "I like pie\n";} );

my $t2 = threads->new(

sub {print "I like cake\n";} );

(62)

Passing parameters

my $t1 = threads->new(\&tsub, "apple"); my $t2 = threads->new(\&tsub, "cherry"); $t1->join; $t2->join; sub tsub { my ($fruit) = @_;

print "I like $fruit pie\n"; }

(63)

Returning from a thread

my $t1 = threads->new(\&tsub, "apple"); my $t2 = threads->new(\&tsub, "cherry"); my $len1 = $t1->join;

print "thread 1 returned $len1\n"; my $len2 = $t2->join;

print "thread 2 returned $len2\n"; sub tsub {

my ($fruit) = @_;

print "I like $fruit pie\n"; return length $fruit;

(64)
(65)

Return context

(66)

Return context

# scalar context

(67)

Return context

# scalar context

my $thr = threads->new(…); # list context

(68)

Return context

# scalar context

my $thr = threads->new(…); # list context

(69)

Return context

# scalar context my $thr = threads->new(…); # list context my ($thr) = threads->new(…); # void context

(70)

Return context

# scalar context my $thr = threads->new(…); # list context my ($thr) = threads->new(…); # void context threads->new(…);

(71)

Return context

# scalar context my $thr = threads->new(…); # list context my ($thr) = threads->new(…); # void context threads->new(…); # inside thread

(72)

Return context

# scalar context my $thr = threads->new(…); # list context my ($thr) = threads->new(…); # void context threads->new(…); # inside thread if (threads->wantarray()) {...}

(73)
(74)

Are threads enabled?

threads not compiled into Perl by default

(75)

Are threads enabled?

threads not compiled into Perl by default

many (most?) distributions build Perl with threads

(76)

Are threads enabled?

threads not compiled into Perl by default

many (most?) distributions build Perl with threads

(77)

Are threads enabled?

threads not compiled into Perl by default

many (most?) distributions build Perl with threads

-

Debian

(78)

Are threads enabled?

threads not compiled into Perl by default

many (most?) distributions build Perl with threads

-

Debian

-

Ubuntu

(79)
(80)

Are threads enabled?

from command line…

perl -V

(81)

Are threads enabled?

from command line…

perl -V

look for “useithreads=define” from program…

(82)

Are threads enabled?

from command line…

perl -V

look for “useithreads=define” from program…

use Config; ...

(83)
(84)
(85)

Sharing basics

all variables are private by default

(86)

Sharing basics

all variables are private by default

(87)

Sharing basics

all variables are private by default

variables must be explicitly shared

(88)

Explicitly Sharing

use threads; use threads::shared; # compile time my $foo :shared; # run time my $bar; share($bar);

(89)

Explicitly Sharing

use threads; use threads::shared; # compile time my $foo :shared; # run time my $bar; share($bar);

(90)

Explicitly Sharing

use threads; use threads::shared; # compile time my $foo :shared; # run time my $bar; share($bar);

(91)

Explicitly Sharing

use threads; use threads::shared; # compile time my $foo :shared; # run time my $bar; share($bar);

(92)
(93)

What can be shared?

(94)

What can be shared?

scalars

(95)

What can be shared?

scalars

• my $foo : shared; arrays

(96)

What can be shared?

scalars

• my $foo : shared; arrays

(97)

What can be shared?

scalars • my $foo : shared; arrays • my @bar : shared; hashes

(98)

What can be shared?

scalars • my $foo : shared; arrays • my @bar : shared; hashes • my %baz : shared;

(99)

Restrictions on

shared variables

basic rule – a shared variable can't store a reference to an unshared variable

(100)

Restrictions on

shared variables

(101)

Restrictions on

shared variables

(102)

Restrictions on

shared variables

my ($foo, $bar, $baz);

(103)

Restrictions on

shared variables

my ($foo, $bar, $baz);

share($foo); share($bar); $foo = 42; # ok

(104)

Restrictions on

shared variables

my ($foo, $bar, $baz);

share($foo); share($bar); $foo = 42; # ok

(105)

Restrictions on

shared variables

my ($foo, $bar, $baz);

share($foo); share($bar); $foo = 42; # ok

$foo = "pony"; # ok $foo = $bar; # ok

(106)

Restrictions on

shared variables

my ($foo, $bar, $baz);

share($foo); share($bar); $foo = 42; # ok

$foo = "pony"; # ok $foo = $bar; # ok $foo = $baz; # ok

(107)

Restrictions on

shared variables

my ($foo, $bar, $baz);

share($foo); share($bar); $foo = 42; # ok $foo = "pony"; # ok $foo = $bar; # ok $foo = $baz; # ok $foo = \$bar; # ok

(108)

Restrictions on

shared variables

my ($foo, $bar, $baz);

share($foo); share($bar); $foo = 42; # ok $foo = "pony"; # ok $foo = $bar; # ok $foo = $baz; # ok $foo = \$bar; # ok

(109)
(110)

my $n :shared = 0; my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; print "\$n = $n\n"; sub tsub { for (1..100_000) { $n++; } }

(111)

my $n :shared = 0; my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; print "\$n = $n\n"; sub tsub { for (1..100_000) { $n++; # RACE CONDITION } }

(112)

use threads::shared; my $foo :shared;

... {

lock($foo);

# $foo is locked until end of block }

(113)

my $n :shared = 0; my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; print "\$n = $n\n"; sub tsub { for (1..100_000) { lock($n); $n++; } }

(114)
(115)

Lock caveats

locks are only advisory

(116)

Lock caveats

locks are only advisory

(117)

Lock caveats

locks are only advisory

can't lock elements of a container:

(118)

Lock caveats

locks are only advisory

can't lock elements of a container:

lock($foo{bar}); # error

(119)
(120)

Thread::Semaphore

Compared to locks:

not tied to scalars/containers

not limited by scope

more flexible than “locked” and “unlocked”

(121)

Thread::Semaphore

->new() ->new(N)

makes new semaphore

initializes counter to N

(122)

Thread::Semaphore

->down() ->down(N)

decreases semaphore's counter by N (defaults to 1)

blocks if counter would become negative

(123)

Thread::Semaphore

->up() ->up(N)

increases semaphore's counter by N (defaults to 1)

unblocks threads waiting on down() if possible

(124)

use Thread::Semaphore; my $n :shared = 0; my $semaphore = Thread::Semaphore->new; my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; sub tsub { for (1..100_000) { $semaphore->down; $n++; $semaphore->up; } }

(125)

# n readers, 1 writer my $READERS = 5;

my $sem = new Thread::Semaphore($READERS); my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; sub tsub { if ($do_read) {

$sem->down(1); read(); $sem->up(1); } elsif ($do_write) {

$sem->down($READERS); write();

$sem->up($READERS); }

(126)
(127)
(128)

Thread::Queue

thread-safe FIFO queues

(129)

Thread::Queue

thread-safe FIFO queues

(130)

Thread::Queue

thread-safe FIFO queues

any number of threads

can pass any datatype supported by threads::shared

(131)

Thread::Queue

thread-safe FIFO queues

any number of threads

can pass any datatype supported by threads::shared

(132)

my $q = new Thread::Queue; $q->enqueue($_) for 1..100_000; my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; sub tsub {

while (my $x = $q->dequeue) {

# process $x }

(133)

my $q = new Thread::Queue; $q->enqueue($_) for 1..100_000; my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; sub tsub {

while (my $x = $q->dequeue) {

# process $x }

(134)

my $q = new Thread::Queue; $q->enqueue($_) for 1..100_000; my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; sub tsub { while (my $x = $q->dequeue) { # process $x } }

(135)

my $q = new Thread::Queue; $q->enqueue($_) for 1..100_000; $q->enqueue(undef); $q->enqueue(undef); my $t1 = threads->new(\&tsub); my $t2 = threads->new(\&tsub); $t1->join; $t2->join; sub tsub {

while (my $x = $q->dequeue) {

# process $x }

(136)
(137)

Thread IDs

(138)

Thread IDs

In main thread:

my $t = threads->new(\&foo); my $tid = $t->tid();

(139)

Thread IDs

In main thread:

my $t = threads->new(\&foo); my $tid = $t->tid();

(140)

Thread IDs

In main thread: my $t = threads->new(\&foo); my $tid = $t->tid(); Inside thread: # class method my $tid = threads->tid();

(141)
(142)

Thread list

(143)

Thread list

Call class method threads->list(). Handy for cleanup:

(144)

Thread list

Call class method threads->list(). Handy for cleanup:

(145)
(146)
(147)

Threads suck

hard to debug

program flow indeterminate

limit to possible speedup

hard to code

(148)
(149)

Java Threads

java threads suck, too

(150)

Java Threads

java threads suck, too

(151)

Java Threads

java threads suck, too

not terribly different from perl threads

but java programmers use threads all the time

(152)
(153)

Perl Threads Suck

(154)

Perl Threads Suck

Memory usage

(155)

Perl Threads Suck

Memory usage

-

no copy-on-write

(156)

Perl Threads Suck

Memory usage

-

no copy-on-write

Many XS modules not thread-safe

(157)

Perl Threads Suck

Memory usage

-

no copy-on-write

Many XS modules not thread-safe

Core not designed to be thread-safe

(158)

Perl Threads Suck

Memory usage

-

no copy-on-write

Many XS modules not thread-safe

Core not designed to be thread-safe

-

unlike JVM

(159)

Perl Threads Suck

Memory usage

-

no copy-on-write

Many XS modules not thread-safe

Core not designed to be thread-safe

-

unlike JVM

forks.pm

-

same syntax as threads.pm, but uses fork instead

(160)

double tot = 0;

for (double i = 0; i <= 1; i += 1e-7) { tot += f(i);

(161)

#pragma omp parallel reduction(+:tot)

double tot = 0;

for (double i = 0; i <= 1; i += 1e-7) { tot += f(i);

(162)

More Information

Perl threads: • perlthrtut • threads • threads::shared • Thread::Queue • Thread::Semaphore

(163)

More Information

pthreads:

• Pthreads Programming (O'Reilly)

• https://computing.llnl.gov/tutorials/ pthreads/

(164)

More Information

OpenMP

• https://computing.llnl.gov/tutorials/ openMP/

(165)

More Information

MPI

• https://computing.llnl.gov/tutorials/ mpi/

(166)

More Information

Future of Parallel Computing

• "Computer Hardware Is Back"

David Patterson, iTunes U, Stanford Computer Systems Colloquiums,

(167)

References

Related documents

Health workers in locations without Internet connectivity can access the system using any phone (satellite, fixed-line, mobile, or community pay phone).. For emerging economies

Nevertheless, the Defendants in both cases resolved to continue to argue that there must be a requirement for a level at which material increase of risk is

The attacker attempts to prevent legitimate users from accessing the information or services by sending large number of fake requests, whereas in a DDoS attack,

On behalf of the state of North Carolina, it is a pleasure to offer warm greetings to everyone attending UNCF’s An Evening of Stars ® Tribute, in honor of Floyd and Norma Young!.

It is possible that colonial ties not only affect the level of food aid shipped from donor to recipient country, but also the responsiveness of aid to recipient needs.. This

UNCHS (Habitat) provides network support services for the sharing and exchange of information on, inter alia, good and best practices, training and human resources development,

As taking into account long lags might be key to appropriately describe certain aspects of the relationship between life expectancy and per capita income (at least for the

Ancaman kepada keselamatan Sabah – pembinaan negara-bangsa di sebalik masyarakat yang berbilang etnik, pelarian dan orang tidak bernegara, dan migran ekonomi, ditambah pula