2. Task – A Task can be understood as a single task or a
process or program executing on a computer.
A Task comprises of
Its own memory address space in which the code and data
of the task are stored
System resources like files and devices
At least one thread which executes the code
Thread – A thread is a single sequential flow of
control within a program.
A thread is a sequence of executing instructions that
can run independently of other threads yet can
directly share data with other threads.
A Thread comprises of
A processor state including current instruction pointer
A stack to store current process state/data
3. In computer science, a Thread is the smallest unit of
processing that can be scheduled by an operating system.
It generally results from a fork of a computer program.
The implementation of threads and processes differs from
one operating system to another, but in most cases, a
thread is contained inside a process.
Multiple threads can exist within the same process and
share resources such as memory, while different
processes do not share these resources.
Consider the Example of a Word Processing Application
i.e., Ms Word. Ms Word is a process and spell-checker
within it is a Thread. And the memory they share is Word
document.
4.
5.
6. A process has separate virtual address
space. Two processes running on the
same system at the same time do not
overlap each other.
Threads are entities within a process. All
threads of a process share its virtual address
space and system resources but they have
their own stack created.
Every process has its own data
segment
All threads created by the process share the
same data segment.
Processes use inter process
communication techniques to interact
with other processes.
Threads do not need inter process
communication techniques because they are
not altogether separate address spaces. They
share the same address space; therefore,
they can directly communicate with other
threads of the process.
Process has no synchronization
overhead in the same way a thread has.
Threads of a process share the same address
space; therefore synchronizing the access to
the shared data within the process's address
space becomes very important.
Child process creation within from a
parent process requires duplication of
the resources of parent process
Threads can be created quite easily and no
duplication of resources is required.
Heavyweight Lightweight
7. Processor (often referred as a micro processor, CPU - Central Processing Unit, brain of
the computer) is the basic computation unit of a computer.
The CPU of a computer is responsible for handling all the instructions it receives from the
hardware and the software running on a computer.
They are very important part of a computer as they are responsible for the functioning of the
computer.
The right image is the top view of a processor and the second one is the bottom view of a
processor.
Every desktop, smartphone, tablet, smartwatch, or any device running an operating system
consists of a processor.
The processors can be of small or big in efficiency and size but no device can work without a
processor.
There are many types of processor that vary widely from company to company and even the
models of the same company.
A processor has two basic components the ALU and the CU.
- ALU (Arithmetic Logic Unit) performs mathematical, logical and decision operations.
- CU (Control Unit) directs the operations handled by the processor.
The number of operations the computer can handle are decided by the number of cores of a
computer .
The processor may have one or more cores in it to perform tasks at a given time.
8. Cores are the parts of a processor which receives
instructions, works on it and gives the results.
In simple words, it is the basic computer unit of a
computer (just read on).
Every processor has core(s) which make it to function.
It can run a single program context (or multiple ones)
maintaining the correct program state, registers, and
correct execution order, and performing the operations
through ALUs.
They are the parts of a processor which do
simultaneous processing of multiple tasks at a given
time.
9.
10. GIL (GLOBAL INTERPRETER LOCK)
Threads are useful in programs which use parallel processing
to perform heavy computations. However, Python has
surprising behavior when it comes to threading, especially
noticeable in case of multicore processors.
Python has Global Interpreter Lock, commonly known as GIL,
similar to a mutex in behavior.
This essentially means is a process can run only one thread
at a time.
When a thread starts running, it acquires GIL and when it
waits for I/O, it releases the GIL, so that other threads of
that process can run.
For e.g.,
Let us suppose process P1 has threads t1 and t2.
Python threads are native threads, that means they are
scheduled by the underlying operating system.
t1 running (acquire GIL) -> t1 waiting for I/O (releases GIL) -> t2
running (acquires GIL, by this time t1 is also ready but GIL is
acquired by t2)
11. Hence, we find that GIL is a major restriction, if we want
to write multi threaded python application that does
heavy CPU bound operations.
Because, real multi threading is not possible, as
effectively the process will be utilizing only one CPU at a
single time even in multicore CPU.
However, in most applications of Python (web
application, sysadmin scripts, etc.), this is not really an
issue as these applications are I/O bound.
As a Python programmer, you never have to deal with
acquiring and releasing GIL unless you are writing C/C++
modules, in that case you should take care of acquiring
and releasing GIL.
12.
13. Python virtual machine (interpreter) executes in the
following manner in an multi-threading environment.
Set the GIL
Switch in a thread to run
Execute either of the following
For a specified number of bytecode instructions, or
If the thread voluntarily yields control (time.sleep(0))
Put the thread back to sleep (switch out thread)
Unlock the GIL
Do it all over again
14. EXITING THREADS
When a thread completes execution of the function it
was created for , it exits.
Threads can also quit by calling an exit function such as
thread.exit(), or any of the standard ways of existing a
python process such as sys.exit() or raising the
SystemExit exception.
15. WHAT IS
'IF __NAME__ == "__MAIN__"' FOR?
The if __name__ == "__main__": ... trick exists in Python so that our
Python files can act as either reusable modules, or as standalone
programs. For example, let’s say that we have two files:
#mymath.py
def square(x):
return x * x
if __name__ == '__main__':
print "test: square(42) ==", square(42)
#mygame.py
import mymath
print "this is mygame."
print mymath.square(17)
16. In this example, we’ve written mymath.py to be both used as a utility
module, as well as a standalone program.
We can run mymath standalone by doing this:
#mymath.py
test: square(42) == 1764
But we can also use mymath.py as a module; let’s see what happens
when we run mygame.py:
#mygame.py
this is mygame.
289
Notice that here we don’t see the ‘test’ line that mymath.py had near the
bottom of its code.
That’s because, in this context, mymath is not the main program. That’s
what the if __name__ == "__main__": ... trick is used for.
modules are objects, and all modules have a built-in attribute
__name__. A module's __name__ depends on how we're using the
module.
If we import the module, then __name__ is the module's filename,
without a directory path or file extension:
17. LIFE WITHOUT THREAD
time.sleep() function to show how thread work.
time.sleep() takes a floating point argument and
sleeps for the given number of seconds , meaning
that execution is temporarily halted for the amount
of time specified.
time.sleep(4) halted for 4 seconds.
From time module we can use sleep as well as
ctime.
from time import sleep, ctime
18. PYTHON THREADING MODULE
Python provides severral modules to support MT
programming, including the thread, threading and Queue
modules.
Programmers can use the thread and threading modules
to create and manage threads.
The thread module provides basic thread and locking
support.
The threading module provides higher-level, fully-
featured thread management.
With Queue modules, user can create a queue data
structure that can be shared across multiple threads.
19. THREAD VS THREADING
Thread Threading
Lower level module Higher level module
No control of when your
process exists. When the
main thread finishes, any
other thread will also die,
without warning or proper
cleanup.
Threadig allows the important
child thread to finish first before
existing
In python 3, import
_thread
In python 3, import threading
20. THE THREAD MODULE
In addition to being able to spawn threads, the
thread module also provides a basic
synchronization data structure called a lock
object ( primitive lock, simple lock, mutual
exclusion lock, mutex, and binary
semaphore).
As we mentioned earlier, such synchronization
primitives go hand in hand with thread
management.
21. THREAD FUNCTIONS AND LOCKTYPE LOCK OBJECT
METHODS.
Function/Method Description
thread Module Functions
start_new_thread(function, args,
kwargs=None)
Spawns a new thread and executes
function with the given args and optional
kwargs
allocate_lock() Allocates LockType lock object
exit() Instructs a thread to exit
LockType Lock Object Methods
acquire(wait=None) Attempts to acquire lock object
locked() Returns True if lock acquired, False
otherwise
release() Releases lock
•The key function of the thread module is start_new_thread().
• It takes a function (object) plus arguments and optionally, keyword arguments.
• A new thread is spawned specifically to invoke the function.
22. USING THREAD AND LOCKS
Rather than using a call to sleep() to hold up the main
thread as in mtsleepA.py, the use of locks makes more
sense.
23. THE THREADING MODULE
We will now introduce the higher-level threading
module, which gives you not only a Thread class
but also a wide variety of synchronization
mechanisms to use to your heart’s content.
24. TABLE 4-2 PRESENTS A LIST OF ALL THE OBJECTS AVAILABLE IN THE
THREADING MODULE.
25. The Thread class of the threading module is your
primary executive object.
It has a variety of functions not available to the
thread module. Table 4-3 presents a
26. Attribute Description
Thread object data
attributes
name The name of a thread.
ident The identifier of a thread.
daemon Boolean flag indicating whether a
thread is daemonic.
LIST OF ATTRIBUTES AND METHODS.
27. Thread object methods
__init__(group=None,
target=None, name=None,
args=(), kwargs={},
verbose=None,
daemon=None)c
Instantiate a Thread object, taking target callable and
any args or kwargs. A name or group can also be
passed but the latter is unimplemented. A verbose flag is
also accepted. Any daemon value sets the
thread.daemon attribute/flag.
start() Begin thread execution.
run() Method defining thread functionality (usually overridden
by application writer in a subclass).
join(timeout=None) Suspend until the started thread terminates; blocks
unless timeout (in seconds) is given.
getName()a Return name of thread.
setName(name)a Set name of thread.
isAlive/is_alive()b Boolean flag indicating whether thread is still running.
isDaemon()c Return True if thread daemonic, False otherwise.
setDaemon(daemonic)c Set the daemon flag to the given Boolean daemonic
value (must be called before thread start().
28. There are a variety of ways by which you can create
threads using the Thread class.
We cover three of them here, all quite similar. Pick the
one you feel most comfortable with, not to mention the
most appropriate for your application and future scalability
(we like the final choice the best):
Create Thread instance, passing in function
Create Thread instance, passing in callable class
instance
Subclass Thread and create subclass instance
29. CREATE THREAD INSTANCE, PASSING IN
FUNCTION
Using the threading Module (mtsleepC.py)
The Thread class from the threading module has a
join() method that lets the main thread wait for
thread completion.
30. CREATE THREAD INSTANCE, PASSING IN
CALLABLE CLASS INSTANCE
A similar outcome to passing in a function when creating a
thread is having a callable class and passing in an
instance for execution—this is the more object-oriented
approach to MT programming.
Such a callable class represents an execution
environment that is much more flexible than a function
or choosing from a set of functions.
You now have the power of a class object behind you, as
opposed to a single function or a list/tuple of functions.
Using Callable Classes (mtsleepD.py)
In this example, we pass in a callable class (instance) as
opposed to just a function.
It presents more of an object-oriented approach than
mtsleepC.py.
31. SUBCLASS THREAD AND CREATE SUBCLASS
INSTANCE
The final introductory example involves subclassing
Thread(), which turns out to be extremely similar to
creating a callable class as in the previous example.
Subclassing is a bit easier to read when you are creating
your threads (lines 29–30).
We will present the code for mtsleepE.py in Example 4-6
as well as the output obtained from its execution, and
leave it as an exercise for you to compare mtsleepE.py to
mtsleepD.py.
Rather than instantiating the Thread class, we subclass it.
This gives us more flexibility in customizing our threading
objects and simplifies the thread creation call.
33. COMPARING SINGLE VS. MULTITHREADED
EXECUTION
The mtfacfib.py script, presented in Example 4-8 compares
execution of the recursive Fibonacci, factorial, and
summation functions.
This script runs all three functions in a single-threaded
manner.
It then performs the same task by using threads to illustrate
one of the advantages of having a threading environment.
Example 4-8. Fibonacci, Factorial, Summation
(mtfacfib.py)
In this MT application, we execute three separate recursive
functions—first in a single-threaded fashion, followed by
the alternative with multiple threads.
34. SYNCHRONIZATION PRIMITIVES
Synchronization in a multithreaded program means serialised
access to a critical resource.
A critical resource is typically a variable in a program that is
shared across multiple threads.
The need for Synchronization of a critical resource arises from
the fact various combinations of read and write sequences
will lead to data anomalies due to premature overwriting of
values by threads followed by reading of wrong values
by the threads.
When multiple threads try to access a resource a race condition
arises.
Race conditions in a multi threaded program leads to
inconsistent reads and writes resulting in data inconsistency and
erroneous behavior of programs due to data inconsistencies.
Synchronization is one of the mechanisms to handle race
conditions in multithreaded programs.
In Python, the following Synchronization primitives are provided
for the multithreaded programs.
35. Lock Objects
In Python, the Lock class of threading module implements
the primitive lock.
The Lock can be acquired and released. When the lock is
in locked state other threads wait for the lock to
be released by the thread. Any thread can release the lock.
RLock Objects
RLock is the reentrant lock provided by python.
A reentrant lock or simply RLock allows itself to be locked
several times.
The RLock is released only after equal number release()
calls as the acquire() calls made to it.
Unlike the primitive lock given by the Lock class the RLock
can only be released by the thread holding the RLock.
36. SEMAPHORES
Semaphores are used when the resources to be shared
among the threads are limited in number.
Semaphore can be acquired 'n' number of times without
waiting where 'n' is number of resources managed by
the Semaphore.
The resources can be sessions, number of threads in a
thread pool and so on.
In python Semaphore is implemented by the Semaphore
class of the Threading Module.
Each call to the acquire() of Semaphore object method
decreases the counter in the Semaphore, till it becomes
zero.
Once the count becomes zero, any further calls to
acquire() will be blocked.