0% found this document useful (0 votes)
31 views81 pages

Unit II

Uploaded by

Shiv Rami
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
31 views81 pages

Unit II

Uploaded by

Shiv Rami
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Unit-II

By:
Mani Butwall
Asst. Prof. (CSE)
Contents
• Exception Handling: Handling an exception, Exception
Hierarchy, The Exception Model, Run Time Errors,
try…….except…….else, try-finally-clause, Argument of an
exception, Python standard exceptions and user defined
exceptions, Handling IO Exceptions.
• Multithreading: Starting a new thread, the threading module,
synchronizing threads, race condition, multithreaded priority
queue.
Errors in Python
• Error in Python can be of two types i.e. Syntax errors and
Exceptions. Errors are the problems in a program due to which
the program will stop the execution. On the other hand,
exceptions are raised when some internal events occur which
changes the normal flow of the program.
• The difference between Syntax Error and Exceptions
• Syntax Error: As the name suggest this error is caused by
wrong syntax in the code. It leads to the termination of the
program.
Exceptions
• Exceptions: Exceptions are raised when the program is
syntactically correct but the code resulted in an error. This
error does not stop the execution of the program, however, it
changes the normal flow of the program.
Introduction
• An exception is an error that happens during execution of a
program. When that error occurs, Python generate an
exception that can be handled, which avoids your program to
crash.
• When these exceptions occur, it causes the current process to
stop and passes it to the calling process until it is handled. If
not handled, our program will crash.
• For example, if function A calls function B which in turn calls
function C and an exception occurs in function C. If it is not
handled in C, the exception passes to B and then to A.
• If never handled, an error message is spit out and our program
come to a sudden, unexpected halt.
Python Exception Handling
◉ We can make certain mistakes while writing a program that lead to errors
when we try to run it. A python program terminates as soon as it encounters
an unhandled error. These errors can be broadly classified into two classes:
1. Syntax errors
2. Logical errors (Exceptions)
◉ Python Syntax Errors
◉ Error caused by not following the proper structure (syntax) of the language is
called syntax error or parsing error.
◉ Let's look at one example:
◉ As shown in the example, an arrow indicates where the parser ran into the
syntax error.
◉ We can notice here that a colon : is missing in the if statement.
Why Exception Handling
• Exceptions are convenient in many ways for handling errors
and special conditions in a program. When you think that you
have a code which can produce an error then you can use
exception handling.
Types of Exceptions
• IOError
• If the file cannot be opened.
• ImportError
• If python cannot find the module
• ValueError
• Raised when a built-in operation or function receives an
argument that has the right type but an inappropriate value
• KeyboardInterrupt
• Raised when the user hits the interrupt key (normally Control-C
or Delete)
• EOFError
• Raised when one of the built-in functions (input() or raw_input())
hits an end-of-file condition (EOF) without reading any data
Syntax to Handle
• except IOError:
• print('An error occurred trying to read the file.')
• except ValueError:
• print('Non-numeric data found in the file.')
• except ImportError:
• print "NO module found"
• except EOFError:
• print('Why did you do an EOF on me?')
• except KeyboardInterrupt:
• print('You cancelled the operation.') except: print('An error
occurred.')
Keyword for Exception Handling

• Try
• Except
• Raise
• Else
• Finally
Handling an Exception (try)
• In Python, exceptions can be handled using a try statement.
• A critical operation which can raise exception is placed inside
the try clause and the code that handles exception is written
in except clause.
• It is up to us, what operations we perform once we have
caught the exception.
Catching Specific Exception (except)
• The code that follows the except statement is the program’s
response to any exceptions in the preceding try clause.
• A try clause can have any number of except clause to handle
them differently but only one will be executed in case an
exception occurs.
Raising an Exception (Raise)
• In Python programming, exceptions are raised when
corresponding errors occur at run time, but we can forcefully
raise it using the keyword raise.
• We can also optionally pass in value to the exception to clarify
why that exception was raised.
Finally Clause
• The try statement in Python can have an
optional finally clause. This clause is executed no matter what,
and is generally used to release external resources.
• For example, we may be connected to a remote data center
through the network or working with a file or working with a
Graphical User Interface (GUI).
• In all these circumstances, we must clean up the resource
once used, whether it was successful or not. These actions
(closing a file, GUI or disconnecting from network) are
performed in the finally clause to guarantee execution.
• Here is an example of file operations to illustrate this.
Example
Else
• A single try statement can have multiple except statements.
This is useful when the try block contains statements that may
throw different types of exceptions.
• You can also provide a generic except clause, which handles
any exception.
• After the except clause(s), you can include an else-clause. The
code in the else-block executes if the code in the try: block
does not raise an exception.
• The else-block is a good place for code that does not need the
try: block's protection.
Syntax
Demonstration-I
Output
Demonstration-II
Output
Demonstration-III
Output
Demonstration-IV
Output
Demonstration-V
Output
Customized Exception
• Python has numerous built-in exceptions that force your
program to output an error when something in the program
goes wrong.
• However, sometimes you may need to create your own
custom exceptions that serve your purpose.
• In Python, users can define custom exceptions by creating a
new class. This exception class has to be derived, either
directly or indirectly, from the built-in Exception class. Most of
the built-in exceptions are also derived from this class.
Multithreading in
Python
Introduction
• A thread is the smallest unit of execution with the
independent set of instructions. It is a part of the process and
operates in the same context sharing program’s runnable
resources like memory.
• For Example, when you are playing a game on your PC, the
game as a whole is a single process, but it consists of several
threads responsible for playing the music, taking input from
the user, running the opponent synchronously, etc. All these
are separate threads responsible for carrying out these
different tasks in the same program.
Thread
• In simple words, a thread is a sequence of such instructions within a
program that can be executed independently of other code. For
simplicity, you can assume that a thread is simply a subset of a
process!
• A thread contains all this information in a Thread Control Block
(TCB):
1. Thread Identifier: Unique id (TID) is assigned to every new thread
2. Stack pointer: Points to thread’s stack in the process. Stack
contains the local variables under thread’s scope.
3. Program counter: a register which stores the address of the
instruction currently being executed by thread.
4. Thread state: can be running, ready, waiting, start or done.
5. Thread’s register set: registers assigned to thread for
computations.
6. Parent process Pointer: A pointer to the Process control block
(PCB) of the process that the thread lives on.
Multiple Threads
• Multiple threads can exist within one process where:
• Each thread contains its own register set and local variables
(stored in stack).
• All thread of a process share global variables (stored in
heap) and the program code.
• Consider the diagram below to understand how multiple
threads exist in memory:
When to Use
• Multithreading is very useful for saving time and improving
performance, but it cannot be applied everywhere.
In the previous example, the music thread is independent of
the thread that takes your input and the thread that takes
your input is independent of the thread that runs your
opponent. These threads run independently because they are
not inter-dependent.
• Therefore, multithreading can be used only when the
dependency between individual threads does not exist.
Benefits of Multithreading
1. It ensures effective utilization of computer system
resources.
2. Multithreaded applications are more responsive.
3. It shares resources and its state with sub-threads (child)
which makes it more economical.
4. It makes the multiprocessor architecture more effective due
to similarity.
5. It saves time by executing multiple threads at the same
time.
6. The system does not require too much memory to store
multiple threads.
Applications
• Web Browsers - A web browser can download any number of
files and web pages (multiple tabs) at the same time and still
lets you continue browsing. If a particular web page cannot be
downloaded, that is not going to stop the web browser from
downloading other web pages.
• Web Servers - A threaded web server handles each request
with a new thread. There is a thread pool and every time a
new request comes in, it is assigned to a thread from the
thread pool.
• Computer Games - You have various objects like cars, humans,
birds which are implemented as separate threads. Also playing
the background music at the same time as playing the game is
an example of multithreading.
• Text Editors - When you are typing in an editor, spell-checking,
formatting of text and saving the text are done concurrently
by multiple threads. The same applies for Word processors
also.
• IDE - IDEs like Android Studio run multiple threads at the same
time. You can open multiple programs at the same time. It
also gives suggestions on the completion of a command which
is a separate thread.
How to create thread in python
• Threads in Python can be created in three ways:
1. Without creating a class
2. By extending Thread class
3. Without extending Thread class
Functions of Thread Class
Method Description

activeCount() Returns the count of Thread objects


which are still alive

currentThread() Returns the current object of the


Thread class.

enumerate() Lists all active Thread objects.

isAlive() Returns true if the thread is still alive.

start() Starts the activity of a thread. It must


be called only once for each thread
because it will throw a runtime error if
called multiple times.
Functions of Thread Class
Method Description
run() This method denotes the activity
of a thread and can be overridden
by a class that extends the Thread
class.
join() It blocks the execution of other
code until the thread on which the
join() method was called gets
terminated.

The getName() method retrieves


getName():
the name of a thread.

The setName() method updates


setName():
the name of a thread.
Without Creating a Class

• Multithreading in Python can be accomplished without


creating a class as well
Output
By Extending Thread Class
• When a child class is created by extending the Thread class,
the child class represents that a new thread is executing some
task. When extending the Thread class, the child class can
override only two methods i.e. the __init__() method and the
run() method. No other method can be overridden other than
these two methods.
Output
Without Extending Thread class

• To create a thread without extending the Thread class


Output
Demonstration-I
Output
Demonstration-II
Output
Deadlocks and Race conditions
• Before learning about deadlocks and race conditions, it'll be
helpful to understand a few basic definitions related to
concurrent programming:

1. Critical Section : It is a fragment of code that accesses or


modifies shared variables and must be performed as an
atomic transaction.
2. Context Switch : It is the process that a CPU follows to store
the state of a thread before changing from one task to
another so that it can be resumed from the same point later.
Deadlock
• Deadlock is a situation where a set of processes are blocked
because each process is holding a resource and waiting for
another resource acquired by some other process.

• Consider an example when two trains are coming toward each


other on the same track and there is only one track, none of
the trains can move once they are in front of each other. A
similar situation occurs in operating systems when there are
two or more processes that hold some resources and wait for
resources held by other(s).
• For example, in the below diagram, Process 1 is holding
Resource 1 and waiting for resource 2 which is acquired by
process 2, and process 2 is waiting for resource 1.
Deadlocks
• Deadlocks are the most feared issue that developers face
when writing concurrent/multithreaded applications in
python. The best way to understand deadlocks is by using the
classic computer science example problem known as
the Dining Philosophers Problem.
• The problem statement for dining philosophers is as follows:
• Five philosophers are seated on a round table with five plates
of spaghetti (a type of pasta) and five forks, as shown in the
diagram.
• At any given time, a philosopher must either be eating or
thinking.
• Moreover, a philosopher must take the two forks adjacent to
him (i.e., the left and right forks) before he can eat the
spaghetti. The problem of deadlock occurs when all five
philosophers pick up their right forks simultaneously.
• Since each of the philosophers has one fork, they will all wait
for the others to put their fork down. As a result, none of
them will be able to eat spaghetti.
• Similarly, in a concurrent system, a deadlock occurs when
different threads or processes (philosophers) try to acquire
the shared system resources (forks) at the same time. As a
result, none of the processes get a chance to execute as they
are waiting for another resource held by some other process.
Race Conditions
• A race condition is an unwanted state of a program which
occurs when a system performs two or more operations
simultaneously. For example, consider this simple for loop:
• If you create n number of threads which run this code at once,
you cannot determine the value of i (which is shared by the
threads) when the program finishes execution.
• This is because in a real multithreading environment, the
threads can overlap, and the value of i which was retrieved
and modified by a thread can change in between when some
other thread accesses it.
Synchronizing threads
• To deal with race conditions, deadlocks, and other thread-
based issues, the threading module provides the Lock object.
• The idea is that when a thread wants access to a specific
resource, it acquires a lock for that resource. Once a thread
locks a particular resource, no other thread can access it until
the lock is released.
• As a result, the changes to the resource will be atomic, and
race conditions will be averted.
• A lock is a low-level synchronization primitive implemented by
the __thread module.
• At any given time, a lock can be in one of 2
states: locked or unlocked. It supports two methods:

• acquire(): When the lock-state is unlocked, calling the


acquire() method will change the state to locked and return.
However, If the state is locked, the call to acquire() is blocked
until the release() method is called by some other thread.

• release(): The release() method is used to set the state to


unlocked, i.e., to release a lock. It can be called by any thread,
not necessarily the one that acquired the lock.
Multithreaded Priority Queue
• The Queue module is primarily used to manage to process
large amounts of data on multiple threads. It supports the
creation of a new queue object that can take a distinct
number of items.
The get() and put() methods are used to add or remove items
from a queue respectively. Below is the list of operations that
are used to manage Queue:
1. get(): It is used to add an item to a queue.
2. put(): It is used to remove an item from a queue.
3. qsize(): It is used to find the number of items in a queue.
4. empty(): It returns a boolean value depending upon
whether the queue is empty or not.
5. full(): It returns a boolean value depending upon whether
the queue is full or not.
Advantages
1. Better utilization of resources
2. Simplifies the code
3. Allows concurrent and parallel occurrence of various tasks
4. Reduces the time consumption or response time, thereby,
increasing the performance.
Disadvantages
1. On a single processor system, multithreading won’t hit the
speed of computation. The performance may downgrade
due to the overhead of managing threads.
2. Synchronization is needed to prevent mutual exclusion while
accessing shared resources. It directly leads to more
memory and CPU utilization.
3. Multithreading increases the complexity of the program,
thus also making it difficult to debug.
4. It raises the possibility of potential deadlocks.
5. It may cause starvation when a thread doesn’t get regular
access to shared resources. The application would then fail
to resume its work.

You might also like