Python的同步原语

前言

在多线程编程中,同步原语(synchronization primitives)是确保线程安全和正确执行的关键。Python 提供了一些基础的同步原语,用于协调线程之间的访问和操作。Python的同步原语包括 Lock、RLock、Semaphore、Event 和 Condition,接下来简单介绍一下他们的使用

Lock

Lock(锁)是最简单也是大家最熟悉的同步原语,相信所有的编程语言中,大伙都接触过并且使用过。它允许一个线程独占对共享资源的访问,防止其他线程在同一时间访问该资源。

import threading

lock = threading.Lock()

count = 0

def add():
    for _ in range(10000):
        
        global count,lock
        lock.acquire()
        count += 1
        lock.release()
threads = []
for _ in range(100):
    thread = threading.Thread(target=add)
    threads.append(thread)
    thread.start()
for t in threads:
    t.join()
print(count)

在上面代码中,我们对一个变量进行加一操作,然后在100各线程中执行,每个线程执行操作时,先获取锁,执行之后在释放锁,这样就避免了竞态条件,确保了最终的计数值是正确的。在测试中你可以去掉锁试试,多测试几次,看是不是每次都能获得到预想的结果。

RLock

RLock(可重入锁)是 Lock 的扩展,它允许同一线程多次获得锁,而不会导致死锁。

import threading

rlock = threading.RLock()

def rlock_test():
    with rlock:
        print("Thread", threading.current_thread().name, "acquired the lock")
        with rlock:
            print("Thread", threading.current_thread().name, "acquired the lock again")

threads = [threading.Thread(target=rlock_test) for i in range(5)]
for t in threads:
    t.start()
    
for t in threads:
    t.join()
   

如果你运行了上面代码,你可以发现所有线程都正常执行了,说明在执行rlock_test()函数时,并没有进入死锁状态,你可以奖RLock换成Lock试试。

Semaphore

Semaphore(信号量)允许多个线程同时访问共享资源。它维护一个计数器,只有在计数器大于零时,线程才能访问资源,并在访问后递减计数器。 信号量在所有语言中,都是一个重要同步原语。

import threading
import time

semaphore = threading.Semaphore(3)

def semaphore_test():
    with semaphore:
        print("Thread", threading.current_thread().name, "is accessing the resource\n")
        # 模拟资源访问时间
        time.sleep(1)

threads = [threading.Thread(target=semaphore_test) for _ in range(12)]

t1 = time.time()
for t in threads:
    t.start()

for t in threads:
    t.join()
interval = time.time() - t1
print(interval)

我们把Semaphore初始化为3,然后执行12个线程,在我的电脑中执行完差不多4s,如果换成了Lock锁,执行时间是12s多,你可以好好理解一下,是不是差不多4个批次?一个批次执行了3个线程?这就是上面说的,信号量允许多个线程同时访问共享资源,记住这一点很重要。

Event

Event(事件)用于线程间通信。一个线程可以设置事件,其他线程可以等待事件的发生。比如在开发中,可能需要等待某个线程完成后,再去执行其他的线程,这个时候可以使用Event

import threading
import time


event = threading.Event()
def wait_for_event():
    print(threading.current_thread().name, "is waiting for the event\n")
    event.wait()
    print(threading.current_thread().name, "got the event\n")

def trigger_event():
    print(threading.current_thread().name, "setting the event\n")
    event.set()

threads = [threading.Thread(target=wait_for_event) for _ in range(5)]
trigger_thread = threading.Thread(target=trigger_event)

for t in threads:
    t.start()

time.sleep(10)
trigger_thread.start()

for t in threads:
    t.join()
trigger_thread.join()

运行上面代码,你可以看到有5个线程打印出了第一个函数中的第一个print,等待trigger_thread执行后,才会继续执行完函数。

Condition

Condition(条件变量)用于复杂的线程同步场景,它通常与锁一起使用,以便线程可以等待某些条件满足。

import threading
import time


condition = threading.Condition()

def consumer(i):
    with condition:
        print(f'Consumer{i} is waiting')
        condition.wait()
        print(f"Consumer{i} got the signal")

def producer():
    with condition:
        print("Producer is setting the condition")
        time.sleep(10)
        print("Producer notify all")
        condition.notify_all()
consumer_threads = []
consumer_threads =[threading.Thread(target=consumer, args=(i,)) for i in range(5)]
producer_thread = threading.Thread(target=producer)

for t in consumer_threads:
    t.start()

producer_thread.start()

for t in consumer_threads:
    t.join()
producer_thread.join()

运行上面代码,可以看到如下结果

Consumer0 is waiting
Consumer1 is waiting
Consumer2 is waiting
Consumer3 is waiting
Consumer4 is waiting
Producer is setting the condition
Producer notify all
Consumer2 got the signal
Consumer4 got the signal
Consumer1 got the signal
Consumer3 got the signal
Consumer0 got the signal

consumer_threads 中的线程等待producer_thread执行**condition.notify_all()**后,才会继续执行。

总结

Python 和其他语言哟杨,同步原语为多线程编程提供了强大的工具,以确保线程安全和正确执行。通过理解和使用这些同步原语,开发者可以有效地避免竞态条件(race conditions)和死锁问题,从而编写出更加可靠和健壮的多线程应用程序。在实际开发中,可能80%的情景之下使用Lock就足够了,但其他的几种同步原语对象我们也要了解,在一些特定情况下对我们很有帮助

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值