Multithreaded development of Python (1)

 

Use Lock and RLock objects

  If multiple threads jointly modify a certain data, unpredictable results may occur. In order to ensure the accuracy of the data, multiple threads need to be modified synchronously. In the Python program, use the object Lock and RLock

Simple thread synchronization can be achieved. Both of these objects have acquire and release methods. For data that requires only one thread to operate at a time, you can put its operation between the acquire and release methods.

The advantage of multi-threading is that it can run multiple tasks at the same time (feeling like this), but when threads need to share data, there may be problems with data being out of sync. The following code demonstrates the use of RLock to achieve thread synchronization.

import threading
import time
class mt(threading.Thread):
    def run(self):
        global x

        lock.acquire()
        for i in range(5):
            x += 10
        time.sleep(1)
        print(x)
        lock.release()

x = 0
lock = threading.RLock()

def main():
    thrs = []
    for item in range(8):
        thrs.append(mt())

    for item in thrs:
        item.start()
if __name__ == '__main__':
    main()

In the above example, a thread class mt with a lock to access the global variable x is customized, and 8 threads are initialized in the main function main () to modify x. At one time, only one thread can operate on x to perform the effect as follows:

50, 100, 150 ... In the Python program, if you want to make the variable object safe in a multi-threaded environment, you can use the Lock object in threading to solve it. The following code demonstrates the process of Lock locking the critical section.

import threading

class ShareCounter:

    def __init__(self, initial_value=0):
        self._value = initial_value
        self._value_lock = threading.Lock()

    def incr(self, delta=1):
        with self._value_lock:
            self._value += delta

    def decr(self, delta=1):
        with self._value_lock:
            self._value -= delta

def test(c):
    for n in range(10000):
        c.incr()

    for n in range(10000):
        c.decr()

if __name__ == '__main__':
    c = ShareCounter()
    t1 = threading.Thread(target=test, args=(c,))
    t2 = threading.Thread(target=test, args=(c,))
    t3 = threading.Thread(target=test, args=(c,))

    t1.start()
    t2.start()
    t3.start()
    print('Runing test')
    t1.join()
    t2.join()
    t3.join()
    
    assert  c._value == 0
    print('Locks good!',c._value) # 0

In the above code, when using the with statement, the Lock object can ensure that the mutually exclusive behavior occurs, that is, only one thread is executed at a time to execute the with statement.

 

Use Condition objects

In Python, you can use the Condition object to process data only after certain events are triggered or when certain conditions are met. The purpose of the Condition object is to support complex thread synchronization problems.

Condition is usually associated with a lock. When you need to share a lock in multiple Conditions, you can pass a Lock / RLock instance, otherwise it will automatically generate a lock. The following code will use

Conditon implements a hide-and-seek game: 1. When the game starts, Seeker first covers his eyes to rule Hider; 2. After Hider receives the notification, he hides himself and then notifies Seeker that he can find it.

import threading, time 

class Hider (threading.Thread): 
    def __init __ (self, cond, name): 
        super (Hider, self) .__ init __ () # Need to execute the initialization function of the parent class first, otherwise name will be overwritten by 
        self.cond = cond 
        self.name = name 

    def run (self): 
        time.sleep (1) # Make sure Seeker first runs 
        self.cond.acquire () # 3, obtain the lock, perform the following operation 
        print ("I have closed my eyes That's it! ") 
        Self.cond.notify () # Notify another to unlock and suspend 
        self.cond.wait () 

        print (self.name,": I have found you ") 
        self.cond.notify () 
        self .cond.release () 

        print ( self.name , ': I won') 


class Seeker (threading.Thread): 
    def __init __ (self, cond, name): 
        super (Seeker, self) .__ init __ () # Need to execute the initialization function of the parent class first, otherwise name will Be covered 
        self.cond = cond 
        self.name = name 

    def run (self): 
        self.cond.acquire () # 1 , Get the lock 
        self.cond.wait () # 2, release the lock occupation, and the thread hangs, know notify () and 
        reoccupy the lock print (self.name, ": I have hidden it, please find me quickly Put ") 
        self.cond.notify () 

        self.cond.wait () 
        self.cond.release () 
        print (self.name,": Found by you, hey ") 

cond = threading.Condition () 
seeker = Seeker (cond, 'seeker') 
hider = Hider (cond, 'hider') 
seeker.start () 
hider.start () 

"" " 
I have closed my eyes! 
seeker: I have hidden it, please find it quickly I put 
hider:I have found your 
hider: I won 
, hey" ""

 

Use Semaphore and BoundedSemaphore objects

In Python, you can use Semaphore and BoundedSemaphore to control the counter in a multi-threaded signal system.

1. Semaphore: class threading. Semaphore is a semaphore that controls access to public resources or critical sections. The semaphore maintains a counter that specifies the number of threads that can simultaneously access resources or enter the critical section, each time

One thread gets the signal, the counter is -1, if the counter is 0, other threads stop accessing.

import threading, time

def fun(semaphore,num):
    semaphore.acquire()
    print("降龙十八掌,发出%d掌"%num)
    time.sleep(3)
    semaphore.release()

if __name__ =='__main__':
    semaphore = threading.Semaphore(2)

    for num in range(4):
        t = threading.Thread(target=fun, args=(semaphore,num))
        t.start()  

After execution, threads 0 and 1 are running at the same time, and 2, 3 are running after 3 seconds.

2. BoundedSemaphore: It will check the value of the internal counter and ensure that it will not be greater than the initial value. If it exceeds it, a ValueError will be raised, which is often used to guard the restricted access to resources.

 

Use Event object

In Python, an event object is one of the simplest communication mechanisms between threads. A thread can activate other threads waiting on an event object. The implementation class of the Event object is threading.Event,

This is a class that implements an event object. An event manages a flag. The flag can be set to true by the set () method or reset to false by the clear () method. The wait () method blocks until the flag is true.

The initial value is false.

import threading, time

event = threading.Event()

def func():
    #
    print("%s wait for event ..."%threading.currentThread().getName())

    # event.wait(timeout) 阻塞线程,直到event对象内部标实位为True,或超时
    event.wait()
    print("%s recv event."%threading.currentThread().getName())


t1 = threading.Thread(target=func)
t2 = threading.Thread(target=func)

t1.start()
t2.start()
time.sleep(2)
print("MainTread set event")
event.set() # 将标识位改为True


"""
Thread-1 wait for event ...
Thread-2 wait for event ...
MainTread set event
Thread-2 recv event.
Thread-1 recv event."""

  

Use Timer object

Timer: Timer, used to call a method after a specified time, the corresponding timer action can be cancelled by the cancel () function.

import threading
def func():
    print("ping")

timer = threading.Timer(5,func)
timer.start()

 

Guess you like

Origin www.cnblogs.com/double-W/p/12685267.html