Python thread programming (Thread)

Posted by dv90 on Wed, 15 Dec 2021 17:32:22 +0100

Thread programming

-1. Basic concepts of thread

1. What's the matter

  1. Threads are called lightweight processes
  2. Threads can also use computer multi-core resources, which is a multitasking programming method
  3. Threads are the smallest unit of system allocation kernel
  4. A thread can be understood as a branch task of a process

2. Thread characteristics

  1. A process can contain multiple threads
  2. Thread is also a running behavior, consuming computer resources
  3. All threads in a thread share the resources of the process
  4. The operation of multiple threads does not affect each other
  5. The creation and destruction of threads consume far less resources than processes
  6. Each thread also has its own ID and other characteristics

0. Creating threads by threading module

1. Create thread object

from threading import Thread
t = Thread()
function: Create thread object
 parameter: target Binding thread function
	args Tuples pass parameters to thread function locations
	kwargs The dictionary passes parameters to thread function keys

2. Start thread

t.start()

3. Recycle thread

t.join([timeout])

4. Code demonstration

"""
thread1.py Thread based usage
 step:
1. Encapsulating thread functions
2.Create thread object
3.Start thread
4.Recycle thread
"""
import os
from threading import Thread
from time import sleep

a = 1
# Thread function
def music():
    for i in range(3):
        sleep(2)
        print('play:Yellow River Chorus %s' % os.getpid())
    global  a
    print("a,",a)
    a = 1000

# Create thread object
t = Thread(target=music)
# Start thread
t.start()
for i in range(3):
    sleep(1)
    print('play:beauty love %s' % os.getpid())
# Recycle thread
t.join()
print('Program end')
print("a,", a)

5. Thread object properties

  1. t.name thread name

  2. t.setName() sets the thread name

  3. t.getName() get thread name

  4. t.is_alive() to see if the thread is in the lifecycle

  5. t.daemon sets the main thread and branch thread to exit, and branch thread also exits To set before start, it is usually not used with join

  6. Code demonstration

    """
    thread3.py
     Thread properties demo
    """
    
    from threading import Thread
    from time import sleep
    
    
    def fun():
        sleep(3)
        print('Thread property test')
    
    
    t = Thread(target=fun, name='ceshi')
    # When the main thread exits, the branch thread also exits. It must be used before start. It is meaningless to join
    t.setDaemon(True)
    t.start()
    print(t.getName())
    t.setName('Tedu')
    print('is alive:', t.is_alive())
    print('daemon', t.daemon)
    
    

6. Custom thread class

  1. Create step
    1. Inherit Thread class
    2. Rewrite__ init__ Method to add its own properties, and use super to load the parent class properties
    3. Override run method
  2. usage method
    1. Instantiate object
    2. Call start to automatically execute the run method
    3. Call join recycle thread

Code demonstration

"""
Custom thread class example
"""

from threading import Thread


# Custom thread class

class ThreadClass(Thread):
    # Override parent init
    def __init__(self, *args, **kwargs):
        self.attr = args[0]
        # Load parent init
        super().__init__()

    # Assume that many steps are required to complete the function
    def f1(self):
        print('1')

    def f2(self):
        print(2)

    # Override run logic call
    def run(self):
        self.f1()
        self.f2()


t = ThreadClass()
t.start()
t.join()

7. A very important exercise I don't understand a lot

from threading import Thread
from time import sleep, ctime


class MyThread(Thread):
    def __init__(self, group=None, target=None, name=None,
                 args=(), kwargs=None, *, daemon=None):
        super().__init__()
        self.fun = target
        self.args = args
        self.kwargs = kwargs

    def run(self):
        self.fun(*self.args, **self.kwargs)


def player(sec, song):
    for i in range(3):
        print("Playing %s : %s" % (song, ctime()))
        sleep(sec)


t = MyThread(target=player, args=(3,), kwargs={'song': 'Quantity'})
t.start()
t.join()

8. Inter thread communication

  1. Communication method

    1. Global traversal is used to communicate between threads
  2. Competition for shared resources

    1. Shared resources: resources that can be operated by multiple processes or threads are called shared resources, and the operation code segment of shared resources is called critical area
    2. Impact: disorderly operation of public resources may lead to data confusion or operation errors At this time, it is often necessary to coordinate the operation order by the synchronous mutual exclusion mechanism
  3. Synchronous mutual exclusion mechanism

    1. Synchronization: synchronization is a cooperative relationship. In order to complete the operation, multiple processes or threads form a coordination and execute the operation in order according to the necessary steps

    ​ 2. Mutual exclusion: mutual exclusion is a constraint relationship. When a process or thread occupies a resource, it will be locked. At this time, other process threads cannot operate the resource until it is unlocked

## 9. Thread synchronization and mutual exclusion method

1. Thread Event code demonstration

from threading import Event
# Create thread event object
e = Event()
# Blocking wait e is set
e.wait([timeout]) 
# Set e to make wait end blocking
e.set() 
# Return e to unset state
e.clear() 
# Check whether the current e is set
e.is_set() 
"""
event Thread mutual exclusion method demonstration
"""

from threading import Event, Thread

s = None  # For communication
e = Event()

def yzr():
    print('Yang Zirong came to worship the mountain')
    global s
    s = 'Heavenly King covering the earth tiger'
    e.set() #Finished sharing resource e settings


t = Thread(target=yzr)
t.start()

print('You're right. The password is your own')
e.wait() #Blocking wait e.set()
if s == 'Heavenly King covering the earth tiger':
    print('pagoda will stop river monster')
    print('Confirmed the eyes,You are the right person')
    e.clear()
else:
    print('Kill him...')

t.join()
print('Program end')

2. Thread Lock code demonstration

from threading import Lock

lock = Lock()Create lock object
lock.acquire() Lock if lock It will be blocked if it is locked and called again
lock.release() Unlock

with lock: Lock
....
....
with Code block unlock automatic unlock
"""
thread_lock
 Thread lock demo
"""

from threading import Thread, Lock

a = b = 0
lock = Lock()


def value():
    while True:
        # Lock
        lock.acquire()
        print('a=%d,b=%d' % (a, b)) if a != b else print('a Not equal to b')
        # Unlock
        lock.release()


t = Thread(target=value)
t.start()
while True:
    # with start locking
    with lock:
        a += 1
        b += 1
    # with unlock automatic unlock

t.join()
print('Program end')

10. Deadlock and its handling

1. Definitions

Deadlock is a blocking phenomenon caused by two or more threads competing for resources or communicating with each other during execution. Without external force, they will not be able to move forward At this time, it is said that the system is in a deadlock state or the system has a deadlock

2. Illustration

3. Deadlock generation conditions

Necessary conditions for deadlock occurrence

  • Mutually exclusive condition: refers to the exclusive use of the allocated resources by the thread, that is, a resource is occupied by only one process within a period of time. If there are other processes requesting resources at this time, the requester can only wait until the process occupying the resources is released.
  • Request and hold condition: refers to that the thread has held at least one resource, but puts forward a new resource request, and the resource has been occupied by other processes. At this time, the requesting thread is blocked, but it still holds the other resources it has obtained.
  • No deprivation condition: the resources obtained by the thread cannot be deprived before they are used up, and can only be released by itself when they are used up. Generally, CPU memory resources can be forcibly allocated and deprived by the system.
  • Loop waiting condition: when a deadlock occurs, there must be a thread resource ring chain, that is, t0 in the process set {T0, T1, T2, ···, Tn} is waiting for a resource occupied by T1; T1 is waiting for resources occupied by T2,..., Tn is waiting for resources occupied by t0.

Causes of deadlock

In short, the causes of deadlock can be summarized into three sentences:

  • The current thread has resources required by other threads
  • The current thread waits for resources already owned by other threads
  • Do not give up their own resources
  1. How to avoid deadlock

Deadlock is a phenomenon we don't want to see. We should try our best to avoid deadlock. By setting some restrictions to destroy one or more of the four necessary conditions for deadlock, deadlock can be prevented. Deadlock prevention is an easy method to implement. However, the restrictions imposed are often too strict, which may lead to the utilization of system resources.

Deadlock code demonstration

from time import sleep
from threading import Thread, Lock


# Transaction class
class Account:
    def __init__(self, _id, balance, lock):
        # user
        self._id = _id
        # deposit
        self.balance = balance
        # lock
        self.lock = lock

    # Withdraw money
    def withdraw(self, amount):
        self.balance -= amount

    # save money
    def deposit(self, amount):
        self.balance += amount

    # balance
    def get_balance(self):
        return self.balance


Tom = Account('Tom', 5000, Lock())
Alex = Account('Alex', 8000, Lock())


def transfer(from_, to, amount):
    # Lock your account
    if from_.lock.acquire():
        # Account decrease
        from_.withdraw(amount)
        sleep(0.5)
        if to.lock.acquire():
            to.deposit(amount)
            to.lock.release()
        from_.lock.release()
    print('Transfer completed %s to%s transfer accounts%d' % (from_._id, to._id, amount))


# transfer(Tom, Alex, 1000)
t1 = Thread(target=transfer, args=(Tom, Alex, 2000))
t2 = Thread(target=transfer, args=(Alex, Tom, 3500))
t1.start()
t2.start()
t1.join()
t2.join()
print('Program end')

Topics: Python Back-end