并发编程
守护进程
若a为b的守护进程,a进程结束,b进程未结束,则会等待进程结束后结束整体进程;
b进程结束,a进程未结束,则会立即结束整体进程
Process.daemon = True
from multiprocessing import Process
import time
def task():
print('zi run')
time.sleep(3)
print('zi over')
if __name__ == '__main__':
p = Process(target=task)
p.daemon = True # 将这个进程设置为了守护进程
p.start()
time.sleep(4)
print('zhu over')
进程安全问题
当并发的多个任务要同时操作公共资源时,就是造成数据错乱的问题
解决方法就是讲并发操作编程串行操作,但是牺牲了效率,提升了安全性
- 将并行改成串行
- 互斥锁
互斥锁
互斥锁是为了让公共内容有序进行
互斥锁内的内容是串行,锁外面的内容还可以是并发
from multiprocessing import Lock
from multiprocessing import Process,Lock
import time,random
def task1(mutex):
for i in range(10000): # 锁外面的内容还是可以实现并发
print(1)
mutex.acquire() # 加锁
print('zi1 run')
time.sleep(3)
print('zi1 over')
mutex.release() # 解锁
def task2(mutex):
for i in range(10000):
print(2)
mutex.acquire() # 加锁
print('zi2 run')
time.sleep(3)
print('zi2 over')
mutex.release() # 解锁
if __name__ == '__main__':
mutex = Lock() # 创建锁
p1 = Process(target=task1,args=(mutex,))
p2 = Process(target=task2, args=(mutex,))
p1.start()
p2.start()
Manager的使用
from multiprocessing import Process,Manager,Lock
import time
def task(data,lock):
lock.acquire()
num = data[0]
time.sleep(0.2)
data[0] = num - 1
lock.release()
print("子 over")
if __name__ == '__main__':
d = [100]
m = Manager() # 创建一个管理器
syncdict = m.list(d) # 让管理器创建一个进程同步的字典
# 创建一个锁
lock = Lock()
ps = []
for i in range(10):
p = Process(target=task,args=(syncdict,lock))
p.start()
ps.append(p)
进程队列
队列 先进先出
from multiprocessing import Queue
q = Queue(2) # 创建队列 并且同时只能存储2个元素
q.put(1)
q.put(2)
# q.put(3,block=True,timeout=3) # 默认是阻塞的 当容器中没有位置了就阻塞 直到有人从里面取走元素为止
print(q.get())
print(q.get())
print(q.get(block=True,timeout=3))# 默认是阻塞的 当容器中没有位置了就阻塞 直到有人存入元素为止
函数调用栈
通过函数调用函数
最先执行的函数反而是最后结束的,最后执行的函数是最先结束的
def a():
b()
def b():
c()
def c():
print('c')
raise Exception
a()
进程间通信几种方式
-
创建一个共享文件
缺点:效率低
优点:理论上交换的数据量非常大
适用于:交互不频繁但是数据量非常大的情况
-
共享内存
缺点:数据量不能太大
优点:效率高
适用于:交互频繁,数据量较小
-
管道
管道也是基于文件的,它是单向的,编程比较复杂
-
socket
编程复杂,更适用于基于网络来交换数据