并发编程-守护进程-互斥锁

守护进程

主进程创建守护进程(子进程)

那么主进程就是被守护进程

  • 守护进程会在主进程代码执行结束后就终止
  • 守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children

注意:进程之间是相互独立的,主进程代码运行结束,守护进程随即终止.

from multiprocessing import Process
import time

def task():
    print('sub start')
    print('sub over')


if __name__ == '__main__':
    p =Process(target=task)
    p.daemon = True  # 将这个进程设置成子进程,必须放在p.start()前面
    p.start()
    print('parent start')
    time.sleep(1)   # 这里加延时,就是为了让子进程运行完毕,否则,就会出现子进程(守护进程)还没有运行完全,主程序(被守护进程)就已经运行完并结束代码了
    print('parent over')
    
# 如果没有在主程序这里加延时,则不会打印子进程,因为在操作系统开启子进程时,主程序代码已经运行完毕.   
parent start
sub start  
sub over
parent over

进程安全问题

因为子进程的内存时相互隔离的,所以进程之间数据不共享;如果多个在子进程同时访问同一个文件,或者打印同一个终端,那么就会带来竞争,竞争带来的结果就是错乱,这个就是进程安全问题.

这里进程1和进程2,之所以把范围放这么大,是为了能显示出问题打印

from multiprocessing import Process

def task1():
    for i in range(10000):
        print('sub1 run')
        print('sub1  over')


def task2():
    for i in range(10000):
        print('sub2 run')
        print('sub2  over')


if __name__ == '__main__':
    p1 = Process(target=task1)
    p2 = Process(target=task2)

    p1.start()
    p2.start()

    
sub1  over
sub2  over
sub1 run
sub2 run
sub1  over
sub2  over

互斥锁(进程同步)

什么是互斥锁?

​ 互相排斥的锁

原理:

​ 就是将要操作公共资源的代码锁起来 以保证同一时间只能有一个进程在执行这部分代码

进程之间数据不共享,但是共享同一套文件系统,同时访问同一个文件,或者打印同一个终端,那么就会产生竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理

为了解决上面出现因为子进程竞争而出现的进程安全问题,为了解决这个问题,我们用到了互斥锁.

from multiprocessing import Process,Lock

def task1(mutex):
    mutex.acquire()
    for i in range(10000):
        print('sub1 run')
        print('sub1  over')
        
    mutex.release()

def task2(mutex):
    mutex.acquire()
    for i in range(10000):
        print('sub2 run')
        print('sub2  over')
    mutex.release()


if __name__ == '__main__':
    mutex = Lock()
    p1 = Process(target=task1,args=(mutex,))
    p2 = Process(target=task2,args=(mutex,))

    p1.start()
    p2.start()

锁的原理

def task1():
    global lock
    if lock == False:
        lock = True
        open("aaa.txt","wt")
        lock = False


def task2():
    global lock
    if lock == False:
        lock = True
        open("aaa.txt","wt")
        lock = False

从这可以看出,锁并不是把数据锁住不让用,而是让代码不执行.

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()


if __name__ == '__main__':
    d = [100]
    m = Manager()  # 创建一个管理器
    sync_list = m.list(d)  # 让管理器创建一个进程同步的列表(也可以是字典等)

    lock = Lock() # 创建一个锁

    ps = []
    for i in range(10):
        p = Process(target=task,args=(sync_list,lock))
        p.start()
        ps.append(p)

    for p in ps:p.join()

    print(d)
    print(sync_list)
    
sub over
sub over
sub over
sub over
sub over
sub over
sub over
sub over
sub over
sub over
[100]
[90]

总结:

加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即将并发改成串行,保证了数据安全,但是牺牲了速度.

虽然可以用文件共享数据实现进程间通信,但问题是:

  • 效率低:共享数据是基于文件,而文件是在硬盘上
  • 需要自己加锁处理

这种方式适合交互不频繁,数据量大的情况,

对于交互频繁,数据量小的情况不合适,因此我们用另外一种解决方案:IPC(进程间通信)--队列+管道

队列

进程间相互隔离,要实现进程间通信(IPC),multiprocess模块支持两种形式:队列和管道,这两种方式都是使用消息传递的

队列是先进先出

from multiprocessing import Queue

q = Queue(2)  # 创建队列,并且同时只能存储两个元素,如果不写,默认为无限大
q.put(1)  # 将数据存入管道
q.put(2)
# q.put(3,block=False,timeout=3)  # block=True表示阻塞,默认为True; timeout=3表示等待延时3s,默认为None;
                               # 当容器中没有位置了就阻塞,等待3秒,在这个时间段有人从管道里面取走一个元素,
                               # 那么元素3就会存入进去,否则就会抛出错误 queue.Full

print(q.get())  # get 是将数据取出来 并且是先进先出
print(q.get())
# print(q.get(block=True,timeout=3)) # 默认是阻塞,直到有人存入元素, 跟存入一样.

转载于:https://www.cnblogs.com/raynduan/p/11286466.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值