Keeping Time, Scheduling Tasks, and Launching Programs 
347
multithreading
To introduce the concept of multithreading, let’s look at an example situa-
tion. Say you want to schedule some code to run after a delay or at a specific 
time. You could add code like the following at the start of your program:
import time, datetime
startTime = datetime.datetime(2029, 10, 31, 0, 0, 0)
while datetime.datetime.now() < startTime:
time.sleep(1)
print('Program now starting on Halloween 2029')
--snip--
This code designates a start time of October 31, 2029, and keeps calling 
time.sleep(1)
until the start time arrives. Your program cannot do anything 
while waiting for the loop of 
time.sleep()
calls to finish; it just sits around 
until Halloween 2029. This is because Python programs by default have a 
single thread of execution.
To understand what a thread of execution is, remember the Chapter 2 
discussion of flow control, when you imagined the execution of a program 
as placing your finger on a line of code in your program and moving to 
the next line or wherever it was sent by a flow control statement. A single-
threaded program has only one finger. But a multithreaded program has mul-
tiple fingers. Each finger still moves to the next line of code as defined by 
the flow control statements, but the fingers can be at different places in the 
program, executing different lines of code at the same time. (All of the pro-
grams in this book so far have been single threaded.)
Rather than having all of your code wait until the 
time.sleep()
func-
tion finishes, you can execute the delayed or scheduled code in a separate 
thread using Python’s 
threading
module. The separate thread will pause 
for the 
time.sleep
calls. Meanwhile, your program can do other work in the 
original thread.
To make a separate thread, you first need to make a 
Thread
object by 
calling the 
threading.Thread()
function. Enter the following code in a new 
file and save it as threadDemo.py:
import threading, time
print('Start of program.')
u def takeANap():
time.sleep(5)
print('Wake up!')
v threadObj = threading.Thread(target=takeANap)
w threadObj.start()
print('End of program.')
Pdf create fillable form - C# PDF Field Edit Library: insert, delete, update pdf form field in C#.net, ASP.NET, MVC, Ajax, WPF
Online C# Tutorial to Insert, Delete and Update Fields in PDF Document
adding an image to a pdf form; convert word document to editable pdf form
Pdf create fillable form - VB.NET PDF Field Edit library: insert, delete, update pdf form field in vb.net, ASP.NET, MVC, Ajax, WPF
How to Insert, Delete and Update Fields in PDF Document with VB.NET Demo Code
edit pdf form; chrome pdf save form data
348   
Chapter 15
At u, we define a function that we want to use in a new thread. To create 
Thread
object, we call 
threading.Thread()
and pass it the keyword argu-
ment 
target=takeANap
v. This means the function we want to call in the new 
thread is 
takeANap()
. Notice that the keyword argument is 
target=takeANap
not 
target=takeANap()
. This is because you want to pass the 
takeANap()
func-
tion itself as the argument, not call 
takeANap()
and pass its return value. 
After we store the 
Thread
object created by 
threading.Thread()
in 
threadObj
we call 
threadObj.start()
w to create the new thread and start executing the 
target function in the new thread. When this program is run, the output 
will look like this:
Start of program.
End of program.
Wake up!
This can be a bit confusing. If 
print('End of program.')
is the last line of 
the program, you might think that it should be the last thing printed. The 
reason 
Wake up!
comes after it is that when 
threadObj.start()
is called, the tar-
get function for 
threadObj
is run in a new thread of execution. Think of it as 
a second finger appearing at the start of the 
takeANap()
function. The main 
thread continues to 
print('End of program.')
. Meanwhile, the new thread 
that has been executing the 
time.sleep(5)
call, pauses for 5 seconds. After it 
wakes from its 5-second nap, it prints 
'Wake up!'
and then returns from the 
takeANap()
function. Chronologically, 
'Wake up!'
is the last thing printed by 
the program.
Normally a program terminates when the last line of code in the file 
has run (or the 
sys.exit()
function is called). But threadDemo.py has two 
threads. The first is the original thread that began at the start of the pro-
gram and ends after 
print('End of program.')
. The second thread is created 
when 
threadObj.start()
is called, begins at the start of the 
takeANap()
func-
tion, and ends after 
takeANap()
returns.
A Python program will not terminate until all its threads have termi-
nated. When you ran threadDemo.py, even though the original thread had 
terminated, the second thread was still executing the 
time.sleep(5)
call.
Passing Arguments to the Thread’s Target Function
If the target function you want to run in the new thread takes arguments, 
you can pass the target function’s arguments to 
threading.Thread()
. For 
example, say you wanted to run this 
print()
call in its own thread:
>>> print('Cats', 'Dogs', 'Frogs', sep=' & ')
Cats & Dogs & Frogs
This 
print()
call has three regular arguments, 
'Cats'
'Dogs'
, and 
'Frogs'
and one keyword argument, 
sep=' & '
. The regular arguments can be passed 
VB.NET Create PDF from PowerPoint Library to convert pptx, ppt to
Convert multiple pages PowerPoint to fillable and editable PDF documents. Easy to create searchable and scanned PDF files from PowerPoint.
add signature field to pdf; change pdf to fillable form
VB.NET Create PDF from Word Library to convert docx, doc to PDF in
Edit Bookmark. Metadata: Edit, Delete Metadata. Form Process. Create PDF files from both DOC and DOCX formats. Convert multiple pages Word to fillable and editable
add fields to pdf form; add an image to a pdf form
Keeping Time, Scheduling Tasks, and Launching Programs 
349
as a list to the 
args
keyword argument in 
threading.Thread()
. The keyword 
argument can be specified as a dictionary to the 
kwargs
keyword argument 
in 
threading.Thread()
.
Enter the following into the interactive shell:
>>> import threading
>>> threadObj = threading.Thread(target=print, args=['Cats', 'Dogs', 'Frogs'], 
kwargs={'sep': ' & '})
>>> threadObj.start()
Cats & Dogs & Frogs
To make sure the arguments 
'Cats'
'Dogs'
, and 
'Frogs'
get passed 
to 
print()
in the new thread, we pass 
args=['Cats', 'Dogs', 'Frogs']
to 
threading.Thread()
. To make sure the keyword argument 
sep=' & '
gets 
passed to 
print()
in the new thread, we pass 
kwargs={'sep': '& '}
to 
threading.Thread()
.
The 
threadObj.start()
call will create a new thread to call the 
print()
function, and it will pass 
'Cats'
'Dogs'
, and 
'Frogs'
as arguments and 
' & '
for the 
sep
keyword argument.
This is an incorrect way to create the new thread that calls 
print()
:
threadObj = threading.Thread(target=print('Cats', 'Dogs', 'Frogs', sep=' & '))
What this ends up doing is calling the 
print()
function and passing its 
return value (
print()
’s return value is always 
None
) as the 
target
keyword 
argument. It doesn’t pass the 
print()
function itself. When passing argu-
ments to a function in a new thread, use the 
threading.Thread()
function’s 
args
and 
kwargs
keyword arguments.
Concurrency Issues
You can easily create several new threads and have them all running at the 
same time. But multiple threads can also cause problems called concurrency 
issues. These issues happen when threads read and write variables at the 
same time, causing the threads to trip over each other. Concurrency issues 
can be hard to reproduce consistently, making them hard to debug.
Multithreaded programming is its own wide subject and beyond the 
scope of this book. What you have to keep in mind is this: To avoid concur-
rency issues, never let multiple threads read or write the same variables. 
When you create a new 
Thread
object, make sure its target function uses only 
local variables in that function. This will avoid hard-to-debug concurrency 
issues in your programs.
no t e
A beginner’s tutorial on multithreaded programming is available at http:// 
nostarch.com/automatestuff/.
VB.NET Create PDF from Excel Library to convert xlsx, xls to PDF
Link: Edit URL. Bookmark: Edit Bookmark. Metadata: Edit, Delete Metadata. Form Process. Create fillable and editable PDF documents from Excel in Visual
acrobat create pdf form; adding text fields to a pdf
C# Create PDF from Excel Library to convert xlsx, xls to PDF in C#
Create fillable and editable PDF documents from Excel in both .NET WinForms and ASP.NET. Create searchable and scanned PDF files from Excel.
adding images to pdf forms; add jpg to pdf form
350   
Chapter 15
Project: multithreaded xkcd downloader
In Chapter 11, you wrote a program that downloaded all of the XKCD 
comic strips from the XKCD website. This was a single-threaded program: 
It downloaded one comic at a time. Much of the program’s running time 
was spent establishing the network connection to begin the download and 
writing the downloaded images to the hard drive. If you have a broadband 
Internet connection, your single-threaded program wasn’t fully utilizing the 
available bandwidth.
A multithreaded program that has some threads downloading comics 
while others are establishing connections and writing the comic image files 
to disk uses your Internet connection more efficiently and downloads the 
collection of comics more quickly. Open a new file editor window and save 
it as multidownloadXkcd.py. You will modify this program to add multithread-
ing. The completely modified source code is available to download from 
http://nostarch.com/automatestuff/.
Step 1: Modify the Program to Use a Function
This program will mostly be the same downloading code from Chapter 11, 
so I’ll skip the explanation for the Requests and BeautifulSoup code. The 
main changes you need to make are importing the 
threading
module and 
making a 
downloadXkcd()
function, which takes starting and ending comic 
numbers as parameters.
For example, calling 
downloadXkcd(140, 280)
would loop over the down-
loading code to download the comics at http://xkcd.com/140, http://xkcd.com/141, 
http://xkcd.com/142, and so on, up to http://xkcd.com/279. Each thread that 
you create will call 
downloadXkcd()
and pass a different range of comics to 
download.
Add the following code to your multidownloadXkcd.py program:
#! python3
# multidownloadXkcd.py - Downloads XKCD comics using multiple threads.
import requests, os, bs4, threading
u os.makedirs('xkcd', exist_ok=True)    # store comics in ./xkcd
v def downloadXkcd(startComic, endComic):
    for urlNumber in range(startComic, endComic):
# Download the page.
print('Downloading page http://xkcd.com/%s...' % (urlNumber))
        res = requests.get('http://xkcd.com/%s' % (urlNumber))
res.raise_for_status()
        soup = bs4.BeautifulSoup(res.text)
# Find the URL of the comic image.
        comicElem = soup.select('#comic img')
if comicElem == []:
print('Could not find comic image.')
C# Create PDF from PowerPoint Library to convert pptx, ppt to PDF
Convert multiple pages PowerPoint to fillable and editable PDF documents. Easy to create searchable and scanned PDF files from PowerPoint.
add forms to pdf; pdf form save with reader
C# Create PDF from Word Library to convert docx, doc to PDF in C#.
Convert multiple pages Word to fillable and editable PDF documents in both .NET WinForms and ASP.NET. Easy to create searchable and scanned PDF files from
allow saving of pdf form; change font pdf form
Keeping Time, Scheduling Tasks, and Launching Programs 
351
else:
            comicUrl = comicElem[0].get('src')
# Download the image.
print('Downloading image %s...' % (comicUrl))
            res = requests.get(comicUrl)
res.raise_for_status()
# Save the image to ./xkcd.
imageFile = open(os.path.join('xkcd', os.path.basename(comicUrl)), 'wb')
for chunk in res.iter_content(100000):
imageFile.write(chunk)
imageFile.close()
# TODO: Create and start the Thread objects.
# TODO: Wait for all threads to end.
After importing the modules we need, we make a directory to store 
comics in u and start defining 
downloadxkcd()
v. We loop through all the 
numbers in the specified range w and download each page x. We use 
Beautiful Soup to look through the HTML of each page y and find the 
comic image z. If no comic image is found on a page, we print a message. 
Otherwise, we get the URL of the image { and download the image |. 
Finally, we save the image to the directory we created.
Step 2: Create and Start Threads
Now that we’ve defined 
downloadXkcd()
, we’ll create the multiple threads 
that each call 
downloadXkcd()
to download different ranges of comics from 
the XKCD website. Add the following code to multidownloadXkcd.py after the 
downloadXkcd()
function definition:
#! python3
# multidownloadXkcd.py - Downloads XKCD comics using multiple threads.
--snip--
# Create and start the Thread objects.
downloadThreads = []             # a list of all the Thread objects
for i in range(0, 1400, 100):    # loops 14 times, creates 14 threads
downloadThread = threading.Thread(target=downloadXkcd, args=(i, i + 99))
downloadThreads.append(downloadThread)
downloadThread.start()
First we make an empy list 
downloadThreads
; the list will help us keep track 
of the many 
Thread
objects we’ll create. Then we start our 
for
loop. Each time 
through the loop, we create a 
Thread
object with 
threading.Thread()
, append 
the 
Thread
object to the list, and call 
start()
to start running 
downloadXkcd()
in the new thread. Since the 
for
loop sets the 
i
variable from 
0
to 
1400
at steps 
of 
100
i
will be set to 
on the first iteration, 
100 
on the second iteration, 
200
on the third, and so on. Since we pass 
args=(i, i + 99)
to 
threading.Thread()
the two arguments passed to 
downloadXkcd()
will be 
0
and 
99
on the first itera-
tion, 
100
and 
199
on the second iteration, 
200
and 
299
on the third, and so on.
C# Create PDF Library SDK to convert PDF from other file formats
Create fillable PDF document with fields. Load PDF from existing documents and image in SQL server. Load PDF from stream programmatically.
create a fillable pdf form from a pdf; create pdf forms
VB.NET Create PDF Library SDK to convert PDF from other file
Create fillable PDF document with fields in Visual Basic .NET application. Load PDF from existing documents and image in SQL server.
changing font in pdf form; adding images to pdf forms
352   
Chapter 15
As the 
Thread
object’s 
start()
method is called and the new thread 
begins to run the code inside 
downloadXkcd()
, the main thread will continue 
to the next iteration of the 
for
loop and create the next thread.
Step 3: Wait for All Threads to End
The main thread moves on as normal while the other threads we create 
download comics. But say there’s some code you don’t want to run in the 
main thread until all the threads have completed. Calling a 
Thread
object’s 
join()
method will block until that thread has finished. By using a 
for
loop 
to iterate over all the 
Thread
objects in the 
downloadThreads
list, the main thread 
can call the 
join()
method on each of the other threads. Add the following 
to the bottom of your program:
#! python3
# multidownloadXkcd.py - Downloads XKCD comics using multiple threads.
--snip--
# Wait for all threads to end.
for downloadThread in downloadThreads:
downloadThread.join()
print('Done.')
The 
'Done.'
string will not be printed until all of the 
join()
calls have 
returned. If a 
Thread
object has already completed when its 
join()
method 
is called, then the method will simply return immediately. If you wanted to 
extend this program with code that runs only after all of the comics down-
loaded, you could replace the 
print('Done.')
line with your new code.
launching other Programs from Python
Your Python program can start other programs on your computer with the 
Popen()
function in the built-in 
subprocess
module. (The P in the name of 
the 
Popen()
function stands for process.) If you have multiple instances of an 
application open, each of those instances is a separate process of the same 
program. For example, if you open multiple windows of your web browser 
at the same time, each of those windows is a different process of the web 
browser program. See Figure 15-1 for an example of multiple calculator pro-
cesses open at once.
Every process can have multiple threads. Unlike threads, a process can-
not directly read and write another process’s variables. If you think of a 
multithreaded program as having multiple fingers following source code, 
then having multiple processes of the same program open is like having 
a friend with a separate copy of the program’s source code. You are both 
independently executing the same program.
If you want to start an external program from your Python script, pass 
the program’s filename to 
subprocess.Popen()
. (On Windows, right-click the 
application’s Start menu item and select Properties to view the application’s 
VB.NET Create PDF from OpenOffice to convert odt, odp files to PDF
Create PDF document from OpenOffice Text Document with embedded Export PDF document from OpenOffice Presentation. ODT, ODS, ODP forms into fillable PDF formats.
allow saving of pdf form; add picture to pdf form
C# Create PDF from OpenOffice to convert odt, odp files to PDF in
Create PDF document from OpenOffice Presentation in both .NET WinForms and ASP.NET NET control to change ODT, ODS, ODP forms to fillable PDF formats in Visual
build pdf forms; cannot save pdf form
Keeping Time, Scheduling Tasks, and Launching Programs 
353
filename. On OS X, 
ctrl
-click the application and select Show Package 
Contents to find the path to the executable file.) The 
Popen()
function will 
then immediately return. Keep in mind that the launched program is not 
run in the same thread as your Python program. 
Figure 15-1: Six running processes of the same calculator program
On a Windows computer, enter the following into the interactive shell:
>>> import subprocess
>>> subprocess.Popen('C:\\Windows\\System32\\calc.exe')
<subprocess.Popen object at 0x0000000003055A58>
On Ubuntu Linux, you would enter the following:
>>> import subprocess
>>> subprocess.Popen('/usr/bin/gnome-calculator')
<subprocess.Popen object at 0x7f2bcf93b20>
On OS X, the process is slightly different. See “Opening Files with 
Default Applications” on page 355.
The return value is a 
Popen
object, which has two useful methods: 
poll()
and 
wait()
.
You can think of the 
poll()
method as asking your friend if she’s fin-
ished running the code you gave her. The 
poll()
method will return 
None
if 
the process is still running at the time 
poll()
is called. If the program has 
terminated, it will return the process’s integer exit code. An exit code is used 
354   
Chapter 15
to indicate whether the process terminated without errors (an exit code 
of 
0
) or whether an error caused the process to terminate (a nonzero exit 
code—generally 
1
, but it may vary depending on the program).
The 
wait()
method is like waiting for your friend to finish working on 
her code before you keep working on yours. The 
wait()
method will block 
until the launched process has terminated. This is helpful if you want your 
program to pause until the user finishes with the other program. The 
return value of 
wait()
is the process’s integer exit code.
On Windows, enter the following into the interactive shell. Note that 
the 
wait()
call will block until you quit the launched calculator program.
u >>> calcProc = subprocess.Popen('c:\\Windows\\System32\\calc.exe')
v >>> calcProc.poll() == None
True
w >>> calcProc.wait()   
0
>>> calcProc.poll()
0
Here we open a calculator process u. While it’s still running, we 
check if 
poll()
returns 
None
v. It should, as the process is still running. 
Then we close the calculator program and call 
wait()
on the terminated 
process w. 
wait()
and 
poll()
now return 
0
, indicating that the process ter-
minated without errors.
Passing Command Line Arguments to Popen()
You can pass command line arguments to processes you create with 
Popen()
To do so, you pass a list as the sole argument to 
Popen()
. The first string in 
this list will be the executable filename of the program you want to launch; 
all the subsequent strings will be the command line arguments to pass to 
the program when it starts. In effect, this list will be the value of 
sys.argv
for the launched program.
Most applications with a graphical user interface (GUI) don’t use com-
mand line arguments as extensively as command line–based or  terminal- 
based programs do. But most GUI applications will accept a single argu-
ment for a file that the applications will immediately open when they 
start. For example, if you’re using Windows, create a simple text file called 
C:\hello.txt and then enter the following into the interactive shell:
>>> subprocess.Popen(['C:\\Windows\\notepad.exe', 'C:\\hello.txt'])
<subprocess.Popen object at 0x00000000032DCEB8>
This will not only launch the Notepad application but also have it 
immediately open the C:\hello.txt file.
Task Scheduler, launchd, and cron
If you are computer savvy, you may know about Task Scheduler on Windows, 
launchd on OS X,  or the cron scheduler on Linux. These well- documented 
Keeping Time, Scheduling Tasks, and Launching Programs 
355
and reliable tools all allow you to schedule applications to launch at specific 
times. If you’d like to learn more about them, you can find links to tutorials 
at http://nostarch.com/automatestuff/.
Using your operating system’s built-in scheduler saves you from writing 
your own clock-checking code to schedule your programs. However, use 
the 
time.sleep()
function if you just need your program to pause briefly. Or 
instead of using the operating system’s scheduler, your code can loop until 
a certain date and time, calling 
time.sleep(1)
each time through the loop.
Opening Websites with Python
The 
webbrowser.open()
function can launch a web browser from your pro-
gram to a specific website, rather than opening the browser application 
with 
subprocess.Popen()
. See “Project: mapIt.py with the 
webbrowser
Module” 
on page 234 for more details.
Running Other Python Scripts
You can launch a Python script from Python just like any other applica-
tion. You just have to pass the python.exe executable to 
Popen()
and the file-
name of the .py script you want to run as its argument. For example, the 
following would run the hello.py script from Chapter 1:
>>> subprocess.Popen(['C:\\python34\\python.exe', 'hello.py'])
<subprocess.Popen object at 0x000000000331CF28>
Pass 
Popen()
a list containing a string of the Python executable’s path 
and a string of the script’s filename. If the script you’re launching needs 
command line arguments, add them to the list after the script’s filename. 
The location of the Python executable on Windows is C:\python34\python 
.exe. On OS X, it is /Library/Frameworks/Python.framework/Versions/3.3/bin/
python3. On Linux, it is /usr/bin/python3.
Unlike importing the Python program as a module, when your Python 
program launches another Python program, the two are run in separate 
processes and will not be able to share each other’s variables.
Opening Files with Default Applications
Double-clicking a .txt file on your computer will automatically launch the 
application associated with the .txt file extension. Your computer will have 
several of these file extension associations set up already. Python can also 
open files this way with 
Popen()
.
Each operating system has a program that performs the equivalent of 
double-clicking a document file to open it. On Windows, this is the 
start
program. On OS X, this is the 
open
program. On Ubuntu Linux, this is the 
see
program. Enter the following into the interactive shell, passing 
'start'
'open'
, or 
'see'
to 
Popen()
depending on your system:
>>> fileObj = open('hello.txt', 'w')
>>> fileObj.write('Hello world!')
12
356   
Chapter 15
>>> fileObj.close()
>>> import subprocess
>>> subprocess.Popen(['start', 'hello.txt'], shell=True)
Here we write 
Hello world!
to a new hello.txt file. Then we call 
Popen()
passing it a list containing the program name (in this example, 
'start'
for 
Windows) and the filename. We also pass the 
shell=True
keyword argument, 
which is needed only on Windows. The operating system knows all of the 
file associations and can figure out that it should launch, say, Notepad.exe to 
handle the hello.txt file.
On OS X, the 
open
program is used for opening both document files and 
programs. Enter the following into the interactive shell if you have a Mac:
>>> subprocess.Popen(['open', '/Applications/Calculator.app/'])
<subprocess.Popen object at 0x10202ff98>
The Calculator app should open.
the unix PhiloSoPhy
Programs well designed to be launched by other programs become more power-
ful than their code alone‮ The Unix philosophy is a set of software design prin-
ciples established by the programmers of the Unix operating system (on which 
the modern Linux and OS X are built)‮ It says that it’s better to write small, limited- 
purpose programs that can interoperate, rather than large, feature-rich applica-
tions‮ The smaller programs are easier to understand, and by being interoper-
able, they can be the building blocks of much more powerful applications‮
Smartphone apps follow this approach as well‮ If your restaurant app needs 
to display directions to a café, the developers didn’t reinvent the wheel by writ-
ing their own map code‮ The restaurant app simply launches a map app while 
passing it the café’s address, just as your Python code would call a function 
and pass it arguments‮
The Python programs you’ve been writing in this book mostly fit the Unix 
philosophy, especially in one important way: They use command line argu-
ments rather than 
input()
function calls‮ If all the information your program 
needs can be supplied up front, it is preferable to have this information passed 
as command line arguments rather than waiting for the user to type it in‮ This 
way, the command line arguments can be entered by a human user or supplied 
by another program‮ This interoperable approach will make your programs 
reusable as part of another program‮
The sole exception is that you don’t want passwords passed as command 
line arguments, since the command line may record them as part of its com-
mand history feature‮ Instead, your program should call the 
input()
function 
when it needs you to enter a password‮
You can read more about Unix philosophy at https://en.wikipedia.org/wiki/
Unix_philosophy/
Documents you may be interested
Documents you may be interested