多进程的详细内容

同步与异步

用来表达任务的提交方式

同步
	提交完任务之后原地等待任务的返回结果,期间不做任何事情

异步
	提交完任务之后不原地等待任务的返回结果,直接去做其他事有结果自动通知

阻塞与非阻塞

用来表达任务的执行状态

阻塞
	阻塞态
非阻塞
	就绪态或者运行态

综合使用

同步阻塞     '效率最低'
同步非阻塞
异步阻塞
异步非阻塞    '效率最高'

创建进程的多种方式

"""
1.鼠标双击软件图片运行
2.python代码创建进程
"""

"""
在不同的操作系统中创建进程底层原理不一样
    windows
        以导入模块的形式创建进程
    linux/mac
        以拷贝代码的形式创建进程
"""

创建子进程方式1:

from multiprocessing import Process
import time


def task(name):
    print('task is running', name)
    time.sleep(3)
    print('task is over', name)


if __name__ == '__main__':
    p1 = Process(target=task, args=('jason',))  # 产生一个对象,参数要用元组括起来
    p1.start()  # 异步操作告诉操作系统创建一个新的进程 并在该进程中执行task函数
    task('tom')  # 这里是同步操作,进行主进程的操作,然后打印主,子进程执行下来立马就主进程执行
    print('主')  # 启动子进程的同时会执行下面的操作,不会等子进程的结果

创建子进程方式2:

import time
from multiprocessing import Process


class MyProcess(Process):  # 继承父类
    def __init__(self, name, age):
        super().__init__()  # 子类调用父类的方法
        self.name = name  # 修改对象中的数据值
        self.age = age

    def run(self):
        print('run is running', self.name, self.age)
        time.sleep(3)
        print('run is over', self.name, self.age)


if __name__ == '__main__':
    obj = MyProcess('jason', 18)   # 利用继承的类产生对象
    obj.start()   # 对象调用父类的start方法创建子进程
    print('主')

进程间数据隔离

同一台计算机上的所个进程数据是严格意义上的物理隔离(默认下)

from multiprocessing import Process
import time

money = 1000


def task():
    global money
    money = 666
    print('子进程的task函数查看money', money)


if __name__ == '__main__':
    p1 = Process(target=task)
    p1.start()  # 创建子进程代码  money = 666
    time.sleep(3)  # 主进程代码等待3秒
    print(money)  # 主进程代码打印money money = 1000

进程的join方法

from multiprocessing import Process
import time


def task(name, n):
    print('%s is running' % name)
    time.sleep(n)
    print('%s in over' % name)


if __name__ == '__main__':
    p1 = Process(target=task, args=('jason', 5))
    p2 = Process(target=task, args=('jason', 6))
    p3 = Process(target=task, args=('jason', 8))
    star_time = time.time()
    p1.start()  # 创建子进程p1
    p2.start()  # 创建子进程p2
    p3.start()  # 创建子进程p3
    p1.join()  # 主程序等待子代码运行结束再执行
    p2.join()  # 主程序等待子代码运行结束再执行
    p3.join()  # 主程序等待子代码运行结束再执行
    print(time.time() - star_time)  # 8秒多
"""由于start是异步,所以3个子进程会同时开始执行,当p1.join等待p1子
进程的时候,也是相当于在等待p2,p3子进程"""

IPC机制

IPC:进程间通信
消息队列:储存数据的地方,所有人都可以存,也都可以取
from multiprocessing import Queue

q = Queue(3)  # 括号内可以指定存数据的个数
q.put(111)  # 往消息队列对方数据.
print(q.full())  # 判断消息队列是否已满False不满
q.put(222)
q.put(333)
print(q.full())  # True,满了

# 从消息队列中取出数据
print(q.get())
print(q.get())
print(q.empty())  # 判断消息队列是否为空。False不为空
print(q.get())
print(q.empty())  # 判断消息队列是否为空。True为空
print(q.get_nowait())

"""
full() empty() 在多进程中都不能使用!!!
"""
子进程在消息队列中添加消息:
from multiprocessing import Queue, Process


def product(q):
    q.put('子进程p添加的数据')  # 添加数据


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


if __name__ == '__main__':
    q = Queue()  # 产生消息队列
    p1 = Process(target=consumer, args=(q,))
    p2 = Process(target=product, args=(q,))
    p1.start()  # 创建子进程p1
    p2.start()  # 创建子进程p2
    print('主')

生产者消费者模型

"""回想爬虫"""
生产者
	负责产生数据的'人'
消费者
	负责处理数据的'人'
    
该模型除了有生产者和消费者之外还必须有消息队列(只要是能够提供数据保存服务和提取服务的理论上都可以)

进程对象的多种方法

1.如何查看进程号
from multiprocessing import Process, current_process

current_process()           # 查看进程
current_process().pid      # 获取进程号
import os
os.getpid()         # 获取进程号
os.getppid()        # 获得子进程的父进程
2.终止进程
p1.terminate()
	ps:计算机操作系统都有对应的命令可以直接杀死进程
3.判断进程是否存货
p1.is_alive()
4.start()		# 自动子进程
5.join()	# 让主程序等待子进程结束才执行

守护进程

守护进程会随着守护的进程结束而立刻结束

from multiprocessing import Process
import time


def task(name):
    print('德玛西亚:%s' % name)
    time.sleep(3)
    print('德玛西亚;%s' % name)


if __name__ == '__main__':
    p1 = Process(target=task, args=('jason',))
    p1.daemon = True  # 将子进程绑定为主进程的守护进程
    p1.start()  # 启动子进程
    time.sleep(1)
    print('主进程结束')
"""德玛西亚:jason
	主进程结束
子进程的另一个打印操作未执行,因为主进程结束了,所以作为守护进程的子进程也直接结束
"""

僵尸进程与孤儿进程

僵尸进程
	进程执行完毕后并不会立刻销毁所有的数据,会有一些信息短暂保留下来
 	比如:进程号、进程执行时间、进程消耗功率等给父进程查看
   ps:所有的进程都会变成僵尸进程

孤儿进程
	子进程正常运行,父进程意外死亡,操作系统针对孤儿进程会派遣福利院管理

多进程数据错乱问题

模拟抢票软件
from multiprocessing import Process
import time
import json
import random


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


# 买票
def buy(name):
    # 再次确认票数
    with open(r'data.json', 'r', encoding='utf8') as f:
        date = json.load(f)
    # 模拟网络延迟效果
    time.sleep((random.randint(1, 3)))  # 延迟时间在1到3之间的整数
    if date.get('ticket_num') > 0:
        date['ticket_num'] -= 1
        with open(r'data.json', 'w', encoding='utf8') as f:
            json.dump(date, f)
        print('%s买票成功' % name)
    else:
        print('余票不足%s没有购买成功' % name)


def run(name):
    search(name)
    buy(name)


if __name__ == '__main__':
    for i in range(10):
        p = Process(target=run, args=('用户%s' % i,))
        p.start()
"""
多进程操作数据很可能会造成数据错乱>>>:互斥锁
	互斥锁
		将并发变成串行 牺牲了效率但是保障了数据的安全
"""
### 多进程实现TCP服务端并发

#### 客户端代码

```python
import socket


client = socket.socket()  # 建立客户端对象
client.connect(('127.0.0.1', 8080))

while True:
    client.send(b'hello word')
    date = client.recv(1024)
    print(date)

服务端代码

import socket
from multiprocessing import Process


def get_server():
    server = socket.socket()  # 产生服务端对象
    server.bind(('127.0.0.1', 8080))  # 建议服务端地址
    server.listen(5)  # 建立半连接池
    return server  # 服务器对象


def get_talk(sock):
    while True:
        date = sock.recv(1024)  # 接收消息
        print(date.decode('utf8'))  # 解码
        sock.send(date.upper())  # 发送


if __name__ == '__main__':
    server = get_server()  # 获取返回值
    while True:
        sock, addr = server.accept()  # 等待通道建立,返回值是通道号和IP地址
        p = Process(target=get_talk, args=(sock,))
        p.start()

互斥锁代码实操

锁:建议只加载操作数据的部分 否则整个程序的效率会极低

from multiprocessing import Process, Lock
import time
import json
import random


def search(name):
    with open(r'date.json', 'r', encoding='utf8') as f:
        date = json.load(f)
    print(f'{name}查看余票,目前余票剩余{date.get("ticket_num")}')


def buy(name):
    # 先查询余票
    with open(r'date.json', 'r', encoding='utf8') as f:
        date = json.load(f)
    time.sleep(random.randint(1, 3))
    if date.get('ticket_num') > 0:
        date['ticket_num'] -= 1
        with open(r'date.json', 'w', encoding='utf8') as f1:
            json.dump(date, f1)
        print(f'{name}买票成功')
    else:
        print(f'{name}买票失败')


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


if __name__ == '__main__':
    mutex = Lock()  # 产生一把锁
    for i in range(10):
        p = Process(target=run, args=(f'用户编号{i}', mutex))
        p.start()
"""
锁有很多种 但是作用都一样
	行锁 表锁
"""
posted @   雪语  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示