This article brings you an introduction to resource sharing and commonly used locking mechanisms between threads in Python multi-threading. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you. .
This article will briefly introduce inter-thread resource sharing and commonly used locking mechanisms in multi-threaded programming.
In multi-thread programming, resource sharing between threads is often involved. Commonly used resource sharing methods are:
Global variables (global)
queue(from queue import Queue)
Commonly used resource sharing lock mechanism:
Lock
RLock
Semphore
Condition
Using global variables can realize resource sharing between threads, keyword global
code demonstration :
from threading import Thread, Lock lock = Lock() total = 0 '''如果不使用lock那么,最后得到的数字不一定为0;同时loack不支持连续多次acquire,如果这样做了的后果是死锁!''' def add(): global total global lock for i in range(1000000): lock.acquire() total += 1 lock.release() def sub(): global total global lock for i in range(1000000): lock.acquire() total -= 1 lock.release() thread1 = Thread(target=add) thread2 = Thread(target=sub) # 将Thread1和2设置为守护线程,主线程完成时,子线程也一起结束 # thread1.setDaemon(True) # thread1.setDaemon(True) # 启动线程 thread1.start() thread2.start() # 阻塞,等待线程1和2完成,如果不使用join,那么主线程完成后,子线程也会自动关闭。 thread1.join() thread2.join() total
Use queue to share resources, queue is thread-safe.
from threading import Thread, Lock from queue import Queue def add(q): if q.not_full: q.put(1) def sub(q): if q.not_empty: recv = q.get() print(recv) q.task_done() if __name__ =='__main__': # 设置q最多接收3个任务,Queue是线程安全的,所以不需要Lock qu = Queue(3) thread1 = Thread(target=add, args=(qu,)) thread2 = Thread(target=sub, args=(qu,)) thread1.start() thread2.start() # q队列堵塞,等待所有任务都被处理完。 qu.join()
Lock
Lock cannot acquire locks continuously, otherwise it will cause deadlock. Competition for Lock resources may lead to deadlock.
Lock will reduce performance.
from threading import Thread, Lock lock = Lock() total = 0 '''如果不使用lock那么,最后得到的数字不一定为0;同时lock不支持连续多次acquire,如果这样做了的后果是死锁!''' def add(): global total global lock for i in range(1000000): lock.acquire() total += 1 lock.release() def sub(): global total global lock for i in range(1000000): lock.acquire() total -= 1 lock.release() thread1 = Thread(target=add) thread2 = Thread(target=sub) # 将Thread1和2设置为守护线程,主线程完成时,子线程也一起结束 # thread1.setDaemon(True) # thread1.setDaemon(True) # 启动线程 thread1.start() thread2.start() # 阻塞,等待线程1和2完成,如果不使用join,那么主线程完成后,子线程也会自动关闭。 thread1.join() thread2.join() total
RLock
RLock can continuously acquire locks, but a corresponding number of releases are required to release the locks
Because it can be acquired continuously Lock, so the function with lock is called inside the function
from threading import Thread, Lock, RLock lock = RLock() total = 0 def add(): global lock global total # RLock实现连续获取锁,但是需要相应数量的release来释放资源 for i in range(1000000): lock.acquire() lock.acquire() total += 1 lock.release() lock.release() def sub(): global lock global total for i in range(1000000): lock.acquire() total -= 1 lock.release() thread1 = Thread(target=add) thread2 = Thread(target=sub) thread1.start() thread2.start() thread1.join() thread2.join() total
Condition condition variable
Condition condition variable obeys the context management protocol: use with Statement acquires the associated lock for the duration of the enclosing block.
The wait() method releases the lock and then blocks until another thread wakes it up by calling notify() or notify_all(). Once awakened, wait() reacquires the lock and returns. A timeout can also be specified.
First start the wait function to receive the signal, and then start the notify function to send the signal
from threading import Thread, Condition '''聊天 Peaple1 : How are you? Peaple2 : I`m fine, thank you! Peaple1 : What`s your job? Peaple2 : My job is teacher. ''' def Peaple1(condition): with condition: print('Peaple1 : ', 'How are you?') condition.notify() condition.wait() print('Peaple1 : ', 'What`s your job?') condition.notify() condition.wait() def Peaple2(condition): with condition: condition.wait() print('Peaple2 : ', 'I`m fine, thank you!') condition.notify() condition.wait() print('Peaple2 : ', 'My job is teacher.') condition.notify() if __name__ == '__main__': cond = Condition() thread1 = Thread(target=Peaple1, args=(cond,)) thread2 = Thread(target=Peaple2, args=(cond,)) # 此处thread2要比thread1提前启动,因为notify必须要有wait接收;如果先启动thread1,没有wait接收notify信号,那么将会死锁。 thread2.start() thread1.start() # thread1.join() # thread2.join()
Semphore
This class implements the semaphore object. The semaphore manages an atomic counter that represents the number of release() calls minus the number of acquire() calls plus an initial value. If necessary, the acquire() method blocks until it can return without making the counter negative. If not given, the value defaults to 1.
#Semaphore 是用于控制进入数量的锁 #文件, 读、写, 写一般只是用于一个线程写,读可以允许有多个 import threading import time class HtmlSpider(threading.Thread): def __init__(self, url, sem): super().__init__() self.url = url self.sem = sem def run(self): time.sleep(2) print("Download {html} success\n".format(html=self.url)) self.sem.release() class UrlProducer(threading.Thread): def __init__(self, sem): super().__init__() self.sem = sem def run(self): for i in range(20): self.sem.acquire() html_thread = HtmlSpider("https://www.baidu.com/{}".format(i), self.sem) html_thread.start() if __name__ == "__main__": # 控制锁的数量, 每次同时会有3个线程获得锁,然后输出 sem = threading.Semaphore(3) url_producer = UrlProducer(sem) url_producer.start()
In multi-process programming, global variables cannot be shared between processes, and queue.Queue cannot be used
Multi-process programming communication requires the use of Queue, Pipe
If you use process pool process programming, you need to use the queue of the Manger instance to achieve communication
The above is the detailed content of An introduction to resource sharing between threads and commonly used locking mechanisms in Python multithreading. For more information, please follow other related articles on the PHP Chinese website!