同步与异步,阻塞与非阻塞,进程,互斥锁

同步与异步,阻塞与非阻塞,进程,互斥锁

今日内容概要

  • 同步与非同步
  • 阻塞与非阻塞
  • 创建进程的多种方式
  • 进程join方法
  • 进程间数据隔离
  • 进程间通讯之ICP机制
  • 进程对象诸多方法
  • 生产者消费者模型
  • 互斥锁

今日内容详细

同步与异步

用来表达任务的提交方式

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

阻塞与非阻塞

用来表达任务的执行状态

阻塞
	阻塞态
非阻塞
	就绪态,运行态

综合使用

同步阻塞
	效率最低,需要一直排队,其他什么都不做
同步非阻塞
	一边做其他事,一边排队,需要在这两件事之间来回切换,效率也是低
异步阻塞
	你可以在等待的时候去做别的事,但你被阻塞在等待排队这件事上不能去做前提是
异步非阻塞
	效率最高,一边做其他事,一边等银行那边给你发消息(你不需要来回切换),然后你还可以干其他事,而排队那边你只需要等那边给你发消息

创建进程的多种方式

"""
1.鼠标双击软件图标
2.python代码创建进程
"""
from multiprocessing import Process
import time


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

"""
在不同的操作系统中创建进程底层原理不一样
windows
    以导入模块的形式创建进程
linux/mac
    以拷贝代码的形式创建进程
"""
if __name__ == '__main__':
    # p1 = Process(target=task, args=('jason',))  # 位置参数
    p1 = Process(target=task, kwargs={'name': 'jason123'})  # 关键字传参
    p1.start()  # 异步 告诉操作系统创建一个新的进程 并在该进程中执行task函数
    task('kevin')  # 同步
    print('主')

from multiprocessing import Process
import time


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(2)
        print('run is over', self.name, self.age)


if __name__ == '__main__':
    obj = MyProcess('jason', 123)
    obj.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()  # 创建子进程
    time.sleep(3)  # 主进程代码等待3秒
    print(money)  # 主进程代码打印money
    
'''子进程与主进程之间的数据是分开的(默认情况下)'''

进程的join方法

from multiprocessing import Process
import time


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


if __name__ == '__main__':
    p1 = Process(target=task, args=('jason1', 1))
    p2 = Process(target=task, args=('jason2', 2))
    p3 = Process(target=task, args=('jason3', 3))
    '''join()  主进程代码等待子进程代码运行结束再执行'''
    start_time = time.time()
    # p1.start()
    # p1.join()
    # p2.start()
    # p2.join()
    # p3.start()
    # p3.join()
    # print(time.time() - start_time)  # 6.275256633758545
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()
    print(time.time() - start_time)  # 3.094999313354492
    
 '''同时进行则会同时异步操作,等待最长时间那个即可继续执行主进程'''

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())  # 111
print(q.get())  # 222
print(q.empty())  # 判断队列是否为空 False
print(q.get())  # 333
print(q.empty())  # 判断队列是否为空 True
# print(q.get())  # 如果队列中没有数据,他就会一直等着,直到拿到数据
print(q.get_nowait())  # 如果队列中没有数据,直接报错,不会等待
'''
full() empty()在多进程中都不能使用!!!
'''

from multiprocessing import Process, Queue


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


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


if __name__ == '__main__':
    q = Queue()
    # 主进程往队列中添加数据
    # q.put('我是主进程添加的数据')
    p1 = Process(target=consumer, args=(q,))
    # p2 = Process(target=product, args=(q,))
    p1.start()
    # p2.start()
    print('主')

生产者消费者模型

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

进程对象的多种方法

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


def task():
    print(current_process())  # <Process(Process-1, started)>
    print(current_process().pid)  # 15536
    print('子', os.getpid())  # 子 15536
    print('获取当前程序的主进程号', os.getppid())  # 获取当前程序的主进程号 7216


if __name__ == '__main__':
    p1 = Process(target=task)
    p1.start() 
    print(current_process())  # <_MainProcess(MainProcess, started)>
    print(current_process().pid)  # 7216
    print('主', os.getpid())  # 主 7216
    
2.终止进程
	p1.terminate()
    ps:计算机操作系统都有对应的命令可以直接杀死进程
3.判断进程是否存活
	p1.is_alive()
4.start()
5.join()

守护进程

守护进程会随着守护的进程结束而立刻结束
	eg:吴勇是张红的守护进程 一旦张红嗝屁了 吴勇立刻嗝屁
    
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=('大张红',))
    p1.daemon = True
    p1.start()
    time.sleep(1)
    print('恕瑞玛皇帝:小吴勇嗝屁了')

僵尸进程与孤儿进程

僵尸进程
	进程执行完毕后并不会立刻销毁所有的数据 会有一些信息短暂保留下来
    比如进程号,进程执行时间,进程消耗功率等给父进程查看
    ps:所有的进程都会变成僵尸进程
孤儿进程
	子进程正常运行 父进程意外死亡 操作系统针对孤儿进程会派遣福利院管理

多进程数据错乱问题

# 模拟抢票软件

from multiprocessing import Process
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):
    search(name)
    buy(name)


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

posted @ 2022-11-18 20:50  lsumin  阅读(40)  评论(0编辑  收藏  举报