python_高级进阶(2)进程与并发

基于unix环境(linux,macOS)

主进程需要等待子进程结束之后,主进程才结束
主进程时刻监测子进程的运行状态,当子进程结束之后,一段时间之内,将子进程进行回收.
为什么主进程不在子进程结束后马上对其回收呢?
主进程与子进程是异步关系.主进程无法马上捕获子进程什么时候结束.
如果子进程结束之后马上再内存中释放资源,主进程就没有办法监测子进程的状态了.
unix针对于上面的问题,提供了一个机制.
所有的子进程结束之后,立马会释放掉文件的操作链接,内存的大部分数据,但是会保留一些内容: 进程号,结束时间,运行状态,等待主进程监测,回收.

僵尸进程:

所有的子进程结束之后,在被主进程回收之前,都会进入僵尸进程状态.

僵尸进程缺点:

如果父进程不对僵尸进程进行回收(wait/waitpid),产生大量的僵尸进程,这样就会占用内存,占用进程pid号.

僵尸进程如何解决

父进程产生了大量子进程,但是不回收,这样就会形成大量的僵尸进程,
解决方式就是直接杀死父进程,将所有的僵尸进程变成孤儿进程进程,由init进行回收.

孤儿进程

父进程由于某种原因结束了,但是你的子进程还在运行中,
这样你的这些子进程就成了孤儿进程.你的父进程如果结束了,
你的所有的孤儿进程就会被init进程的回收,init就变成了你的父进程,对你进行回收.

串行

并发是以效率优先的,但是目前我们的需求: 顺序优先.
 多个进程共强一个资源时, 要保证顺序优先: 串行,一个一个来
由并发变成了串行,牺牲了运行效率,但避免了竞争
 from multiprocessing import Process
 import time
 import random
 import os

 def task1():
     print(f'{os.getpid()}开始打印了')
     time.sleep(random.randint(1,3))
     print(f'{os.getpid()}打印结束了')

 def task2():
     print(f'{os.getpid()}开始打印了')
     time.sleep(random.randint(1,3))
     print(f'{os.getpid()}打印结束了')

 def task3():
     print(f'{os.getpid()}开始打印了')
     time.sleep(random.randint(1,3))
     print(f'{os.getpid()}打印结束了')

 if __name__ == '__main__':

     p1 = Process(target=task1)
     p2 = Process(target=task2)
     p3 = Process(target=task3)

     p1.start()
     p2.start()
     p3.start()
加锁:由并发变成了串行,牺牲了运行效率,但避免了竞争

使用join阻塞版本

from multiprocessing import Process
 import time
 import random
 import os

 def task1(p):
     print(f'{p}开始打印了')
     time.sleep(random.randint(1,3))
     print(f'{p}打印结束了')

 def task2(p):
     print(f'{p}开始打印了')
     time.sleep(random.randint(1,3))
     print(f'{p}打印结束了')

 def task3(p):
     print(f'{p}开始打印了')
     time.sleep(random.randint(1,3))
     print(f'{p}打印结束了')

 if __name__ == '__main__':

     p1 = Process(target=task1,args=('p1',))
     p2 = Process(target=task2,args=('p2',))
     p3 = Process(target=task3,args=('p3',))

     p2.start()
     p2.join()
     p1.start()
     p1.join()
     p3.start()
     p3.join()

互斥锁,锁.

lock与join的区别.
共同点: 都可以把并发变成串行, 保证了顺序.
不同点: join人为设定顺序,lock让其争抢顺序,保证了公平性.
from multiprocessing import Process
from multiprocessing import Lock
import time
import random
import os

def task1(p,lock):
    '''
    一把锁不能连续锁两次
    lock.acquire()
    lock.acquire()
    lock.release()
    lock.release()
    '''
    lock.acquire()
    print(f'{p}开始打印了')
    time.sleep(random.randint(1,3))
    print(f'{p}打印结束了')
    lock.release()

def task2(p,lock):
    lock.acquire()
    print(f'{p}开始打印了')
    time.sleep(random.randint(1,3))
    print(f'{p}打印结束了')
    lock.release()

def task3(p,lock):
    lock.acquire()
    print(f'{p}开始打印了')
    time.sleep(random.randint(1,3))
    print(f'{p}打印结束了')
    lock.release()

if __name__ == '__main__':

    mutex = Lock()
    p1 = Process(target=task1,args=('p1',mutex))
    p2 = Process(target=task2,args=('p2',mutex))
    p3 = Process(target=task3,args=('p3',mutex))

    p2.start()
    p1.start()
    p3.start()

进程之间的通信:

# from multiprocessing import Process
# from multiprocessing import Lock
# import json
# import time
# import os
# import random
#
#
# def search():
#     time.sleep(random.randint(1,3))  # 模拟网络延迟(查询环节)
#     with open('ticket.json',encoding='utf-8') as f1:
#         dic = json.load(f1)
#         print(f'{os.getpid()} 查看了票数,剩余{dic["count"]}')
#
#
# def paid():
#     with open('ticket.json', encoding='utf-8') as f1:
#
#         dic = json.load(f1)
#     if dic['count'] > 0:
#         dic['count'] -= 1
#         time.sleep(random.randint(1,3))  # 模拟网络延迟(购买环节)
#         with open('ticket.json', encoding='utf-8',mode='w') as f1:
#             json.dump(dic,f1)
#         print(f'{os.getpid()} 购买成功')
#
#
# def task(lock):
#     search()
#     lock.acquire()
#     paid()
#     lock.release()
#
# if __name__ == '__main__':
#     mutex = Lock()
#     for i in range(6):
#         p = Process(target=task,args=(mutex,))
#         p.start()


# 当很多进程抢一个资源(数据)时, 你要保证顺序(数据的安全),一定要串行.
# 互斥锁: 可以公平性的保证顺序以及数据的安全.

# 基于文件的进程之间的通信:
    # 效率低.
    # 自己加锁麻烦而且很容易出现死锁.

基于队列通信

队列: 把队列理解成一个容器,这个容器可以承载一些数据,
队列的特性: 先进先出永远保持这个数据. FIFO(first in first out).
# from multiprocessing import Queue
# q = Queue()
# def func():
#     print('in func')
# q.put(1)
# q.put('alex')
# q.put([1,2,3])
# q.put(func)
#
#
# print(q.get())
# print(q.get())
# print(q.get())
# f = q.get()
# f()


# from multiprocessing import Queue
# q = Queue(3)
#
# q.put(1)
# q.put('alex')
# q.put([1,2,3])
# # q.put(5555)  # 当队列满了时,在进程put数据就会阻塞.
# # q.get()
#
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())  # 当数据取完时,在进程get数据也会出现阻塞,直到某一个进程put数据.


# from multiprocessing import Queue
# q = Queue(3)  # maxsize
#
# q.put(1)
# q.put('alex')
# q.put([1,2,3])
# q.put(5555,block=False)
#
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get(timeout=3))  # 阻塞3秒,3秒之后还阻塞直接报错.
# print(q.get(block=False))

# block=False 只要遇到阻塞就会报错.
原文地址:https://www.cnblogs.com/SkyRabbit/p/11389619.html