多进程与互斥锁

多进程与互斥锁

创建进程的多种方式

方式一:
from multiprocessing import Process
import time


def task(name):
    print(f'子进程{name}正在运行')
    time.sleep(3)
    print(f'子进程{name}执行完毕')


if __name__ == '__main__':
    p = Process(target=task, args=('joseph',))  # 创建一个进程对象
    p.start()  # 开始子进程执行
    print('主进程执行')
# 在不同的操作系统中因为底层原理有区别所有在windows中创建进程就像是在导模块
# 我们需要使用if __name__ == __main__ 来当作启动脚本启动代码
# 而在linux和mac中则就不需要这种启动脚本但是我们为了系统的兼容性的话那么我们也应该去写一个上面那种启动脚本
方式二:
from multiprocessing import Process
import time


class MyProcess(Process):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print(f'子进程{self.name}正在运行')
        time.sleep(3)
        print(f'子进程{self.name}执行完毕')


if __name__ == '__main__':
    obj = MyProcess('joseph')
    obj.start()
    print('正在执行主进程')

image

TCP端并发

from multiprocessing import Process
import time


def task(name, n):
    print(f'子进程{name}正在执行')
    time.sleep(n)
    print(f'子进程{name}执行完毕')


if __name__ == '__main__':
    p1 = Process(target=task, args=('joseph', 1))  # args通过元组的形式给函数传参
    p1.start()  # 开始执行子进程
    p1.join()  # 主进程等待子进程结束后再运行
    print('主进程')  # 最后执行

image

join方法

from multiprocessing import Process
import time


def task(name, n):
    print(f'子进程{name}正在执行')
    time.sleep(n)
    print(f'子进程{name}执行完毕')


if __name__ == '__main__':
    p1 = Process(target=task, args=('joseph', 1))  # args通过元组的形式给函数传参
    p2 = Process(target=task, args=('alice', 2))
    p3 = Process(target=task, args=('trump', 5))
    start_time = time.time()
    p1.start()  # 开始执行子进程
    p1.join()  # 主进程等待子进程结束后再运行
    p2.start()
    p2.join()
    p3.start()
    p3.join()
    end_time = time.time() - start_time
    print(end_time)
    print('主进程')
# 如果等待它一次执行那么执行时间就会很长,8.649637937545776


from multiprocessing import Process
import time


def task(name, n):
    print(f'子进程{name}正在执行')
    time.sleep(n)
    print(f'子进程{name}执行完毕')


if __name__ == '__main__':
    p1 = Process(target=task, args=('joseph', 1))  # args通过元组的形式给函数传参
    p2 = Process(target=task, args=('alice', 2))
    p3 = Process(target=task, args=('trump', 5))
    start_time = time.time()
    p1.start()  # 开始执行子进程
    p2.start()
    p3.start()
    p1.join()  # 主进程等待子进程结束后再运行
    p2.join()
    p3.join()
    end_time = time.time() - start_time
    print(end_time)
    print('主进程')  # 只要调换下位置让他们先开始执行那么结果就是同时运行进入io态,结束

image

进程数据之间的关系

from multiprocessing import Process

count = 999


def task():
    global count
    count = 666
    print('子进程打印的money', count)  # 666


if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.join()
    print('主进程', count)  # 999
print(count)  # 999

生产者模型和消费者模型

三种关系

​ 生产者,缓冲区,消费者

两类对象

​ 三者的关系分别是:生产者和消费者(互斥和同步),生产者和生产者(互斥),消费者和消费者(互斥)

一个交易场所

​ 交易场所就是生产者和消费者进行数据交换的仓库,相当于一个缓冲区,生产者负责把数据放到缓冲区中去,而消费者则就是把缓冲区的数据拿出来进行处理

生产者和消费者之间的特点

​ 1.生产者只会关心缓冲区,不需要关心具体的消费者的情况

​ 2.对于消费者而言,不需要关心具体的生产者它也是只需要关心缓冲区是否还有数据存在

​ 3.生产者生产的时候消费者不能进行消费,消费者进行消费的时候生产者不能进行生产。相当于是一种互斥关系,也就是生产者和消费者同时只能由一个访问缓冲区

​ 4.缓冲区为空的时候不能进行消费

​ 5.反之,缓冲区满时不能生产

image

进程的相关方法

from multiprocessing import Queue  # 导入对列

q = Queue(3)  # 这个数字是可以定义的,我们查看源代码的时候发现他是的最大值为2147483647
q.put(999)  # 往对列增加值  # 如果增加多出对列最大数那么就会停在那里等待有人将一个值取出它填充进去
q.full()  # 查看对列是否已经存满
q.get()  # 取值  # 如果取值过多可能超出对列范围那么就会停在那里不动直到有一个值给她取
q.empty()  # 查看队列是否已经被取空
q.get_nowait()  # 取值  # 只要我拿不到值号,咱俩谁都别想好过,我直接报错

from multiprocessing import Queue, Process


def procedure(q):
    q.put('子进程procedure往列队中添加了数据')
if __name__ == '__main__':
    p = Process(target=task, args=('joseph',))  # 创建一个进程对象
    p.start()  # 开始子进程执行
    print(p.terminate())  # None  销毁子进程
    print(p.is_alive())  # 判断是否存活
    print('主进程执行')

print(current_process().pid)  # 查看进程号
print(os.getpid())  # 查看进程号
print(os.getppid())  # 查看父进程号

IPC机制

1.主进程与子进程之间的通信
2.子进程与子进程之间的通信
from multiprocessing import Queue, Process


def procedure(q):
    q.put('子进程procedure往列队中添加了数据')


def consumer(q):
    print('子进程consumer往列队中添加了数据', q.get())


if __name__ == '__main__':
    q = Queue()
    # q.put('主进程向对列中添加了新的数据')
    p1 = Process(target=procedure, args=(q,))
    p2 = Process(target=consumer, args=(q,))
    p1.start()  # 子进程consumer往列队中添加了数据
    # 子进程procedure往列队中添加了数据主进程执行
    p1.join()
    p2.start()
    p2.join()
    print('主进程执行')

守护模式

from multiprocessing import Process
import time


def task(name):
    print(f'子进程{name}正在运行')
    time.sleep(3)
    print(f'子进程{name}执行完毕')


if __name__ == '__main__':
    p = Process(target=task, args=('joseph',))  # 创建一个进程对象
    p.daemon = True  # 将子进程设置成父进程的守护进程,只要父进程一结束那么就立即结束
    p.start()  # 开始子进程执行
    # p.join()
    print('主进程执行')

image

僵尸进程和孤儿进程

僵尸进程的产生

​ 僵尸状态是一个比较特殊的状态,当进程退出并且父进程没有读到子进程退出时返回码时就会产生僵尸进程。僵尸进程会中止状态保持在进程表中,并且会一致等待父进程读取退出码状态,所以只要子进程退出,父进程还在运行但父进程没有读进程状态,子进程进入僵尸状态。

孤儿进程

​ 一个父进程退出,而他的一个或多个子进程还在运行,那么这些子进程就会成为孤儿进程。孤儿进程将被init进程所收养,并由init进程对他们完成状态收集工作,。子进程死亡需要父进程来处理,那么一维者正常进程应该是子进程先于父进程死亡。当父进程先于子进程死亡时,子进程死亡时没有父进程处理,那么这个死亡的子进程就是孤儿进程。但孤儿进程和僵尸进程不同的是由于父进程已经死亡,系统会帮助父进程挥手孤儿进程。所以孤儿进程实际上是不占用资源的,因为他终究是被系统回收了。不会像僵尸进程那样占用id损害运行系统。

image

互斥锁

模拟12306抢票
from multiprocessing import Process
import time
import json
import random


def search(name):
    with open(r'data.json', 'r', encoding='utf-8')as f:
        data = json.load(f)
    print('%s正在查票,当前前往理想国的票还剩:%s张' % (name, data.get('ticket_num')))


def buy(name):
    with open(r'data.json', 'r', encoding='utf-8')as f:
        data = json.load(f)
    time.sleep(random.randint(1, 3))
    if data.get('ticket_num') > 0:
        data['ticket_num'] -= 1
        with open(r'data.json', 'w', encoding='utf-8')as f:
            json.dump(data, f)
        print('%s买票成功' % name)
    else:
        print('%s很倒霉,没有抢到票,今晚睡不踏实了' % name)


def run(name):
    search(name)
    buy(name)
    
    
if __name__ == '__main__':
    l1 = ['joseph', 'Alice', 'Kevin', 'Trump', 'jason']
    for i in l1:
        p = Process(target=run, args=('用户名%s' % i,))
        p.start()
        p.join()

image

posted @ 2022-08-09 19:28  Joseph-bright  阅读(110)  评论(0编辑  收藏  举报