同步与异步
1同步
所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列
要么成功都成功,失败都失败,两个任务的状态可以保持一致。
2异步
所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了
至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。
阻塞与非阻塞
阻塞和非阻塞这两个概念与程序(线程)等待消息通知(无所谓同步或者异步)时的状态有关。也就是说阻塞与非阻塞主要是程序(线程)等待消息通知时的状态角度来说的
同步/异步与阻塞/非阻塞
1.同步阻塞形式
效率最低。
进程调用函数后,进程需要等待函数的返回值,在等待的时候,该进程处于挂起状态,当函数返回之后,系统切换为内核态,将该进程改变为就绪态,进入工作队列,等待CPU调度。
2.异步阻塞形式
效率低下
和同步类似,但进程只需等待函数返回收到,即可将进程转换为可运行状态,进程和函数约好使用回调或通知方式进行通信,等到处理完成,函数通过约好的方式将结果发送给进程。
3.同步非阻塞形式
实际上是效率低下的。
进程调用函数后,进程会继续运行,但由于函数在没有执行完成之前没有返回值,进程只能通过轮询进程和函数共享资源的方式来知道函数是否完成。
4.异步非阻塞形式
效率更高,
进程调用函数后,进程会继续运行,进程和函数约好使用回调或通知方式进行通信,等到处理完成,函数通过约好的方式将结果发送给进程。
进程的创建与结束
# 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('tom')
# 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(3)
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=66
print('子进程的task函数查看money',money)
if __name__ == '__main__':
p1=Process(target=task)
p1.start()
time.sleep(3)
print(money)
子进程的task函数查看money 66
1000
进程的join方法
from multiprocessing import Process
import time
def task(name,n):
print(f'{name} is running')
time.sleep(n)
print(f'{name} is over')
if __name__ == '__main__':
# p1 = Process(target=task, args=('jason', 1))
p1 = Process(target=task, args=('jason', 1))
p2 = Process(target=task, args=('jason', 2))
p3 = Process(target=task, args=('jason', 3))
start_time=time.time()
# print(start_time)
p1.start()
p1.join()
p2.start()
p2.join()
p3.start()
p3.join()
# print(time.time())
print(time.time()-start_time)
#jason is running
#jason is over
#jason is running
#jason is over
#jason is running
#jason is over
#6.255166292190552
IPC机制
Queue([maxsize])
创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。
参数 :maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。
底层队列使用管道和锁定实现。
Queue([maxsize])
创建共享的进程队列。maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。底层队列使用管道和锁定实现。另外,还需要运行支持线程以便队列中的数据传输到底层管道中。
Queue的实例q具有以下方法:
q.get( [ block [ ,timeout ] ] )
返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止。block用于控制阻塞行为,默认为True. 如果设置为False,将引发Queue.Empty异常(定义在Queue模块中)。timeout是可选超时时间,用在阻塞模式中。如果在制定的时间间隔内没有项目变为可用,将引发Queue.Empty异常。
q.get_nowait( )
同q.get(False)方法。
q.put(item [, block [,timeout ] ] )
将item放入队列。如果队列已满,此方法将阻塞至有空间可用为止。block控制阻塞行为,默认为True。如果设置为False,将引发Queue.Empty异常(定义在Queue库模块中)。timeout指定在阻塞模式中等待可用空间的时间长短。超时后将引发Queue.Full异常。
q.qsize()
返回队列中目前项目的正确数量。此函数的结果并不可靠,因为在返回结果和在稍后程序中使用结果之间,队列中可能添加或删除了项目。在某些系统上,此方法可能引发NotImplementedError异常。
q.empty()
如果调用此方法时 q为空,返回True。如果其他进程或线程正在往队列中添加项目,结果是不可靠的。也就是说,在返回和使用结果之间,队列中可能已经加入新的项目。
q.full()
如果q已满,返回为True. 由于线程的存在,结果也可能是不可靠的(参考q.empty()方法)。。
q.close()
关闭队列,防止队列中加入更多数据。调用此方法时,后台线程将继续写入那些已入队列但尚未写入的数据,但将在此方法完成时马上关闭。如果q被垃圾收集,将自动调用此方法。关闭队列不会在队列使用者中生成任何类型的数据结束信号或异常。例如,如果某个使用者正被阻塞在get()操作上,关闭生产者中的队列不会导致get()方法返回错误。
q.cancel_join_thread()
不会再进程退出时自动连接后台线程。这可以防止join_thread()方法阻塞。
q.join_thread()
连接队列的后台线程。此方法用于在调用q.close()方法后,等待所有队列项被消耗。默认情况下,此方法由不是q的原始创建者的所有进程调用。调用q.cancel_join_thread()方法可以禁止这种行为。
代码
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.get())#333
print(q.empty())# 判断队列是否为空 True
# print(q.get_nowait())
"""
full() empty() 在多进程中都不能使用!!!
"""
from multiprocessing import Queue , Process
def product(q):
q.put('子进程p添加的数据')
def consument(q):
print('子进程获取列表中的数据',q.get())
if __name__ == '__main__':
q = Queue()
p1=Process(target=consument,args=(q,))
p2=Process(target=product,args=(q,))
p1.start()
p2.start()
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(f'my name is {name}')
time.sleep(3)
print(f'my name is {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()
"""
多进程操作数据很可能会造成数据错乱>>>:互斥锁
互斥锁
将并发变成串行 牺牲了效率但是保障了数据的安全
"""
标签:__,name,队列,print,time,进程
From: https://www.cnblogs.com/bnmm/p/16903922.html