-
-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Changes to code, documentation and examples to support multi-threaded…
… workbook generation.
- Loading branch information
Showing
4 changed files
with
221 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
#!/usr/bin/perl | ||
|
||
############################################################################### | ||
# | ||
# Example of multi-threaded workbook creation with Excel::Writer::XLSX. | ||
# In this example, each thread waits for a process-wide lock to do its own clean-up. | ||
# | ||
# Copyright 2000-2020, John McNamara, [email protected] | ||
# | ||
|
||
use strict; | ||
use warnings; | ||
use Excel::Writer::XLSX; | ||
use Excel::Writer::XLSX::Utility; | ||
use threads; | ||
use threads::shared; | ||
|
||
############################################################################### | ||
# | ||
# Declare the shared variable $cleanup_lock_counter. | ||
# | ||
my $cleanup_lock_counter = 0; | ||
share $cleanup_lock_counter; | ||
|
||
############################################################################### | ||
# | ||
# Generate workbooks in multiple concurrent threads. | ||
# | ||
my %operators = ( | ||
addition => '+', | ||
subtraction => '-', | ||
multiplication => '*', | ||
division => '/', | ||
exponentiation => '^', | ||
); | ||
while ( my ( $operation, $operator ) = each %operators ) { | ||
threads->create( make_runnable( $operation, $operator, 300, 300 ) ); | ||
} | ||
$_->join foreach threads->list(); | ||
|
||
############################################################################### | ||
# | ||
# Create the runnable for a thread to generate workbook files | ||
# and destroy its temporary files in a controlled manner. | ||
# | ||
sub make_runnable { | ||
my ( $operation, $operator, $num_rows, $num_cols ) = @_; | ||
sub { | ||
my @workbookObjects; | ||
|
||
{ # increment the shared variable $cleanup_lock_counter. | ||
lock $cleanup_lock_counter; | ||
++$cleanup_lock_counter; | ||
} | ||
|
||
# Make the workbook and store the workbook object. | ||
push @workbookObjects, | ||
make_workbook( $operation, $operator, $num_rows, $num_cols ); | ||
|
||
{ # decrement the shared variable $cleanup_lock_counter. | ||
lock $cleanup_lock_counter; | ||
--$cleanup_lock_counter; | ||
cond_signal $cleanup_lock_counter; | ||
} | ||
|
||
# Wait for the shared variable $cleanup_lock_counter to be zero. | ||
lock $cleanup_lock_counter; | ||
cond_wait $cleanup_lock_counter while $cleanup_lock_counter > 0; | ||
|
||
# Destruction of temporary files associated with each workbook object. | ||
$_->DESTROY foreach grep { defined $_; } @workbookObjects; | ||
cond_signal $cleanup_lock_counter; | ||
|
||
}; | ||
} | ||
|
||
############################################################################### | ||
# | ||
# Create a Excel::Writer::XLSX file. | ||
# | ||
sub make_workbook { | ||
|
||
my ( $operation, $operator, $num_rows, $num_cols ) = @_; | ||
my $long_name = "Table of $operation ($num_rows by $num_cols)"; | ||
my $workbook = Excel::Writer::XLSX->new("$long_name.xlsx") or return; | ||
my $worksheet = $workbook->add_worksheet( ucfirst($operation) ); | ||
$worksheet->hide_gridlines(2); | ||
my $title_format = | ||
$workbook->add_format( size => 15, bold => 1, num_format => '@' ); | ||
my $header_format = $workbook->add_format( bg_color => 46 ); | ||
$worksheet->write( 0, 0, $long_name, $title_format ); | ||
$worksheet->write( 2, 0, $operator, $header_format ); | ||
|
||
$worksheet->write( $_ + 2, 0, $_, $header_format ) foreach 1 .. $num_rows; | ||
$worksheet->write( 2, $_, $_, $header_format ) foreach 1 .. $num_cols; | ||
|
||
foreach my $row ( 3 .. ( 2 + $num_rows ) ) { | ||
foreach my $col ( 1 .. $num_cols ) { | ||
$worksheet->write( $row, $col, | ||
'=' | ||
. xl_rowcol_to_cell( $row, 0, 0, 1 ) | ||
. $operator | ||
. xl_rowcol_to_cell( 2, $col, 1, 0 ) ); | ||
} | ||
} | ||
|
||
# Generate file. | ||
$workbook->close(); | ||
|
||
# Return workbook object to caller, to control clean-up of temporary files. | ||
$workbook; | ||
|
||
} | ||
|
||
__END__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
#!/usr/bin/perl | ||
|
||
############################################################################### | ||
# | ||
# Example of multi-threaded workbook creation with Excel::Writer::XLSX. | ||
# In this example, a shared queue collects references to the temporary directories | ||
# and these temporary directories are cleaned up when the process ends. | ||
# | ||
# Copyright 2000-2020, John McNamara, [email protected] | ||
# | ||
|
||
use strict; | ||
use warnings; | ||
use Excel::Writer::XLSX; | ||
use Excel::Writer::XLSX::Utility; | ||
use threads; | ||
use Thread::Queue; | ||
|
||
############################################################################### | ||
# | ||
# Declare the shared queue $cleanup_queue. | ||
# | ||
my $cleanup_queue = Thread::Queue->new; | ||
|
||
############################################################################### | ||
# | ||
# Generate workbooks in multiple concurrent threads. | ||
# | ||
my %operators = ( | ||
addition => '+', | ||
subtraction => '-', | ||
multiplication => '*', | ||
division => '/', | ||
exponentiation => '^', | ||
); | ||
while ( my ( $operation, $operator ) = each %operators ) { | ||
threads->create( make_runnable( $operation, $operator, 300, 300 ) ); | ||
} | ||
$_->join foreach threads->list(); | ||
$cleanup_queue->end; | ||
1 while $cleanup_queue->dequeue; | ||
|
||
############################################################################### | ||
# | ||
# Create the runnable for a thread to generate workbook files | ||
# and destroy its temporary files in a controlled manner. | ||
# | ||
sub make_runnable { | ||
my ( $operation, $operator, $num_rows, $num_cols ) = @_; | ||
sub { | ||
my $workbook = | ||
make_workbook( $operation, $operator, $num_rows, $num_cols ); | ||
$cleanup_queue->enqueue( $workbook->{_tempdir_object} ); | ||
}; | ||
} | ||
|
||
############################################################################### | ||
# | ||
# Create a Excel::Writer::XLSX file. | ||
# | ||
sub make_workbook { | ||
|
||
my ( $operation, $operator, $num_rows, $num_cols ) = @_; | ||
my $long_name = "Table of $operation ($num_rows by $num_cols)"; | ||
my $workbook = Excel::Writer::XLSX->new("$long_name.xlsx") or return; | ||
my $worksheet = $workbook->add_worksheet( ucfirst($operation) ); | ||
$worksheet->hide_gridlines(2); | ||
my $title_format = | ||
$workbook->add_format( size => 15, bold => 1, num_format => '@' ); | ||
my $header_format = $workbook->add_format( bg_color => 46 ); | ||
$worksheet->write( 0, 0, $long_name, $title_format ); | ||
$worksheet->write( 2, 0, $operator, $header_format ); | ||
|
||
$worksheet->write( $_ + 2, 0, $_, $header_format ) foreach 1 .. $num_rows; | ||
$worksheet->write( 2, $_, $_, $header_format ) foreach 1 .. $num_cols; | ||
|
||
foreach my $row ( 3 .. ( 2 + $num_rows ) ) { | ||
foreach my $col ( 1 .. $num_cols ) { | ||
$worksheet->write( $row, $col, | ||
'=' | ||
. xl_rowcol_to_cell( $row, 0, 0, 1 ) | ||
. $operator | ||
. xl_rowcol_to_cell( 2, $col, 1, 0 ) ); | ||
} | ||
} | ||
|
||
# Generate file. | ||
$workbook->close(); | ||
|
||
# Return workbook object to caller, to control clean-up of temporary files. | ||
$workbook; | ||
|
||
} | ||
|
||
__END__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters