并发编程2

创建进程的多种方式

1.鼠标双击一个程序图标的过程就是在创建一个进程 进程就是在电脑的内存空间获取一块内存用来运行程序
2.用模块创建进程 (创建进程的两种方式)

from multiprocessing import Process
import time

# 创建一个函数
def course(name):
    print('%s正在干饭' % name)
    time.sleep(9)
    print('%s吃饱啦!!!' % name)


if __name__ == '__main__':
    # windows系统需要在脚本下创建进程 否则的话会一直循环导入
    p = Process(target=course, args=('summer',))  # 创建一个进程
    p.start()  # 启动一个进程(异步操作)
    course('哈哈啊哈')  # 函数调用是同步操作
    print('我是主进程')

------------

	创建进程的代码在不同的操作系统中 底层原理有区别!!!
	在windows中 创建进程类似于导入模块
		if __name__ == '__main__':  启动脚本
	在mac、linux中 创建进程类似于直接拷贝
		不需要启动脚本 但是为了兼容性 也可以使用

------------


# 创建一个类
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(4)
        print('你好哇!')


if __name__ == '__main__':
    obj = MyProcess('summer')
    obj.start()
    print('主进程先打印')

join方法

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(4)
        print('你好哇!')


if __name__ == '__main__':
    obj = MyProcess('summer')
    obj.start()
    obj.join()  # 根据写入的位置来控制先执行子进程还是先执行主进程
    print('主进程后打印')


------------
from multiprocessing import Process
import time
def course(name,n):
    print('%s正在干饭' % name)
    time.sleep(n)
    print('%s吃饱啦!!!' % name)

if __name__ == '__main__':
    p1 = Process(target=course,args=('summer',1))
    p2 = Process(target=course,args=('sun',2))
    p3 = Process(target=course, args=('sum', 3))
    start_time = time.time()
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()
    end_time = time.time() - start_time
    print('总耗时:%s' % end_time)
    print('主进程')

运行结果1:
image
运行结果2:
image

进程间数据默认隔离

# 多个进程间数据是默认相互隔离的 如果真的想要交互,可以借助于管道和队列 
from multiprocessing import Process

money = 9999

def run():
    global money
    money = 6666
    print('子进程',money)

if __name__ == '__main__':
    p = Process(target=run ,args=())
    p.start()
    p.join()
    print('主进程',money)

代码运行结果:
image

进程间通信IPC机制

IPC机制:1.主进程与子进程通信
         2.子进程与主进程通信
需要通过队列来实现进程之间的交互
创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。 
from multiprocessing import Queue, Process
def consumer(q):
    q.put('子进程consumer往队列中添加了数据')

def procedure(q):
    print('子进程的procedure从队列中获取数据',q.get())


if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=consumer,args=(q,))
    p2 = Process(target=procedure,args=(q,))
    p1.start()
    p2.start()
    print('主进程')

image

生产者消费者模型

什么是生产者消费者模式?
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

进程相关方法

1.cmd终端查看进程号 输入命令tasklist
2.代码查看进程号
3.销毁子进程
	p1.terminate()
4.判断进程是否存活
	p1.is_alive()
from multiprocessing import current_process  # 获取进程号的模块1
from multiprocessing import Process
import os   # 获取进程号的模块2
import time


def run():
    print('haha')
    time.sleep(4)
    print('子进程的进程号',current_process().pid)  # 子进程的进程号 219436
    print('我是os方法子进程号',os.getpid())  # 我是os方法子进程号 219436
    print('我是os方法主进程号',os.getppid())  #  我是os方法主进程号 225196

if __name__ == '__main__':
    p1 = Process(target=run,)
    p1.start()
    p1.join()
    print('主进程的进程号',current_process().pid)  # 主进程的进程号 225196
    print('我是os方法主进程号',os.getpid())  # 我是os方法主进程号 225196

image

守护进程

from multiprocessing import Process
import time


def task(name):
    print('子进程:%s存活' % name)
    time.sleep(3)
    print('子进程:%s over' % name)

if __name__ == '__main__':
    p = Process(target=task, args=('summer',))
    p.daemon = True  # 将子进程设置为守护进程:主进程代码结束 子进程立刻结束
    p.start()
    print('主进程!')

僵尸进程与孤儿进程


僵尸进程
	进程已经运行结束 但是相关的资源并没有完全清空
 	需要父进程参与回收
孤儿进程
	父进程意外死亡 子进程正常运行 该子进程就称之为孤儿进程
 	孤儿进程也不是没有人管 操作系统会自动分配福利院接收

互斥锁

将并发变成串行 虽然牺牲了程序的执行效率但是保证了数据安全如何使用
	from multiprocessing import Process, Lock
	mutex = Lock()
	mutex.acquire()  # 抢锁
	mutex.release()  # 释放锁
强调
	互斥锁只应该出现在多个程序操作数据的地方 其他位置尽量不要加
	ps:以后我们自己处理锁的情况很少 只需要知道锁的功能即可
from multiprocessing import Process , Lock
import time
import json
import random


# 查票
def search(name):
    with open(r'data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    print('%s在查票 当前余票为:%s' % (name, data.get('ticket_num')))


# 买票
def buy(name):
    # 再次确认票
    with open(r'data.json', 'r', encoding='utf8') 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='utf8') as f:
            json.dump(data, f)
        print('%s买票成功' % name)
    else:
        print('%s很倒霉 没有抢到票' % name)


def run(name,mutex):
    search(name)
    mutex.acquire()  # 抢锁
    buy(name)
    mutex.ralease() # 释放锁

if __name__ == '__main__':
    # 1.先产生锁
    mutex = Lock()
    for i in range(10):
        p = Process(target=run, args=('用户%s'%i, mutex))
        p.start()


posted @ 2022-08-09 22:14  Hsummer  阅读(26)  评论(0编辑  收藏  举报