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

守护进程

主进程建立守护进程(子进程)python

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

  • 守护进程会在主进程代码执行结束后就终止
  • 守护进程内没法再开启子进程,不然抛出异常: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

进程安全问题

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

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

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

互斥锁(进程同步)

什么是互斥锁?操作系统

​ 互相排斥的锁code

原理:队列

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

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

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

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)) # 默认是阻塞,直到有人存入元素, 跟存入同样.
相关文章
相关标签/搜索