主要内容:
- 小目标:掌握进程同步机制
- 主要内容:Lock
如果看完这篇文章,你还是搞不懂并发同步及锁机制,
你来找我,我保证不打你,我给你发100的大红包。
1. 同步机制
- 并发编程中存在异步问题,如何处理?
使用同步机制,
常见的同步机制包括锁,信号量;
同步机制: 一个例子:公共资源,互斥锁,AB两个进程
修改公共资源流程
进程修改公共资源,需要获取锁;
修改资源;
释放锁;
两个进程:
A进程获取锁,同时去修改公共资源;
进程调度切换,执行B进程;
B进程去获取锁,但是A进程已经占有锁,B进程被挂起;
A进程修改完毕,释放锁;
B进程被唤起,修改资源并释放锁;
2. Value与Array自带锁机制
Value与Array创建对象参数:
Value(typecode_or_type, *args, lock=True)Array(typecode_or_type, size_or_initializer, *, lock=True)
lock默认值为True:代表支持锁机制;
相关方法:
使用方式:
lock = val.get_lock()#打印lock信息print(lock)val.acquire()#打印lock信息print(lock)val.value = 100val.release()
结果:每次lock之后,锁会显示状态;
3. 锁机制应用
两个进程使用同步机制对Value对象修改:
主进程加100000次;子进程减100000次;
代码如下:
import multiprocessingfrom multiprocessing import Queuefrom multiprocessing import Value, Arrayg_value = Value('i', 0)#对g_value处理封装成函数def deal(gvalue, val): gvalue.acquire() gvalue.value += val gvalue.release()#进程函数, 共享内存必须通过参数传入def func(gvalue): i = 0 while i < 100000: #加1 deal(gvalue, 1) i += 1if __name__ == "__main__": print("g_value init value:", g_value.value) #全局消息队列 main_msgq = Queue() #消息队列必须通过参数传入到子进程,否则无效 p = multiprocessing.Process(target=func, args=(g_value,)) p.start() i = 0 while i < 100000: #减1 deal(g_value, -1) i += 1 p.join() print("g_value end value:", g_value.value)
结果:符合预期,最后g_value的值为0;
g_value init value: 0g_value end value: 0
4. 重入锁:Lock
- Lock相关方法:
方法说明:
一个例子:
lock = Lock()lock.acquire()#此处处理公共资源lock.release()
注意:
acquire与release必须成对出现;
lock.acquire中可以设置非阻塞模式:block=False,如果获取失败返回False
- 死锁问题
一个进程获取锁之后,再次获取,就会造成死锁; 例:
lock = Lock()lock.acquire()lock.acquire()#处理公共资源lock.release()lock.release()
一般没人这么做,但是有人这么做:
lock = Lock()lock.acquire()def do(): lock.acquire() #处理公共资源 lock.release()lock.release()
解决方式:重入锁;
5. 冲入锁:RLock
RLock:可以被一个程多次获取; 使用方式与Lock类似; 例如:
rlock = RLock()rlock.acquire()rlock.acquire()print(rlock)rlock.release()rlock.release()print('over')
不会死锁
6. 信号量:Semaphore
Semaphore:可以设置同时被占有的次数;
相关方法:
Semaphore使用方式与Lock类似,但是它可以指定被占有次数; 例如:
sem = Semaphore(2)print('init:', sem.get_value())sem.acquire()print('acquire 1:', sem.get_value())sem.acquire()print('acquire 2:', sem.get_value())sem.release()print('release 1:', sem.get_value())sem.release()print('release 2:', sem.get_value())
结果:
init: 2acquire 1: 1acquire 2: 0release 1: 1release 2: 2
总结:
- Lock,RLock,Semaphore原理与使用方式类似,在掌握Lock后,在理解其他就比较容易;
- 互斥所,信号量这种同步机制在其他一些语言中也同样适用;
- Lock,RLock适用于同一时刻只能一个进程占有场景;
- Semaphore比较灵活,可以设置同时占有的数量;