python31 网络并发编程方法
同步与异步
用来表达任务的提交方式
同步
提交完任务之后原地等待任务的返回结果 期间不做任何事
异步
提交完任务之后不原地等待任务的返回结果 直接去做其他事 有结果自动通知
阻塞与非阻塞
用来表达任务的执行状态
阻塞
阻塞态
非阻塞
就绪态、运行态
总结
同步阻塞
同步非阻塞
异步阻塞
异步非阻塞(******)
效率最高
同步、异步,与阻塞、非阻塞不相关。
同步、异步强调的是结果。
阻塞和非阻塞强调的是时间,是否等待。
同步与异步区别在于:调用者是否得到了想要的最终结果。
同步就是一直要执行到返回最终结果。
异步就是直接返回了,但是返回的不是最终的结果,调用者不能通过这种调用得到结果,还要通过被调用者,使用其他方式通知调用者,来取回最终结果。
阻塞与非阻塞的区别在于,调用者是否还能干其他的事情。
阻塞,调用者只能干等。
非阻塞,调用者可以先忙一会别的,不用一直等。
联系:
同步阻塞:调用者阻塞,直到等到拿到最终结果。(打饭模型,什么事情也不敢,就等着打饭,打饭是结果,什么也不干,一直在等着,同步加阻塞)
同步非阻塞:(等着打饭,但是可以玩会手机,看看电视,打饭是结果,但是不用一直在等着)
异步阻塞:(我要打饭,你说等着较好,并没有返回饭给我,我啥事不干,就干等着饭好了叫我)
异步非阻塞:回调的话。(我要打饭,你说等较好,并没有返回饭给我,可以在旁边看看电视,玩玩手机,饭好了叫我)
同步IO、异步IO、IO多路复用
IO模型:
IO分为两个阶段。
1)数据准备阶段。
2)内核空间复制回用户进程缓冲区阶段。
发生IO的时候:
1、内核从输入设备读、写数据(淘米,把米放锅里煮饭)
2、进程从内核复制数据(盛饭,从内核这个锅把饭装到碗里面来)
创建进程的两种方式
"""
1.鼠标双击软件图标
2.python代码创建进程
"""
1、利用函数创建
from multiprocessing import Process
import time
def task(name):
print('task is running',name)
time.sleep(1)
print('task is over', name)
if __name__ == '__main__':
p1 = Process(target=task,args=('jason',)) # 位置参数
# p1 = Process(target=task,kwargs={'name':'jason123'}) # 关键字参数
p1.start() # 异步 告诉操作系统创建一个新的进程 并在该进程中执行task函数
# task() # 同步
print('主程序')
"""
在不同的操作系统中 创建进程底层原理不一样
windows
以导入模块的形式创建进程
linux/mac
以拷贝代码的形式创建进程
"""
2、利用类创建
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(2) # 主进程代码等待2秒
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))
# p1.start() # 异步
# p1.join()
# print('主程序')
stat_time = time.time()
p1.start()
p1.join()
p2.start()
p2.join()
p3.start()
p3.join()
# p1.join()
# p2.join()
# p3.join()
print(time.time() - stat_time) # 6秒多
IPC机制
IPC:进程间通信
消息队列:存储数据的地方 所有人都可以存 也都可以取
from multiprocessing import Queue
q = Queue(3) # 括号内可以指定存储数据的个数
# 往消息队列中存放数据
q.put(111)
print(q.full()) # 判断消息队列是否已满
q.put(222)
q.put(333)
print(q.full()) # 判断消息队列是否已满
# 从消息队列中取数据
print(q.get())
print(q.get())
print(q.empty()) # 判断队列是否为空
print(q.get())
print(q.empty()) # 判断队列是否为空
print(q.get()) # 取数据 无数据会原地等待
# print(q.get_nowait()) # 也是取数据 但是如果队列里面没有数据会报错
'''full() empty() 在多进程中都不能使用!!!!'''
from multiprocessing import Process, Queue
def producer(q):
q.put('子进程q添加的数据')
def consumer(q):
print('子进程获取队列中的数据', q.get())
if __name__ == '__main__':
q = Queue()
# 主进程往队列中添加数据
q.put('我是主进程添加的数据')
p1 = Process(target=consumer, args=(q,))
# p2 = Process(target=producer, args=(q,))
p1.start()
# p2.start()
print('主进程')
生产者消费者模型
生成者
负责产生数据的'人'
消费者
负责处理数据的'人'
该模型除了有生产者和消费者之外还必须有消息队列(只要是能够提供数据保存服务和提取服务的理论上都可以)
生产者消费者模型
在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。
为什么要使用生产者和消费者模式
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。
什么是生产者消费者模式
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
进程对象的多种方法
1.如何查看进程号
from multiprocessing import Process,current_process
current_process()
print(current_process().pid)
import os
print(os.getpid())
print(os.getppid())
2.终止进程
p1.terminate()
ps:计算机操作系统都有对应的命令可以直接杀死进程
3.判断进程是否存活
p1.is_alive()
5.start() 创建进程
6.join() 阻塞等待进程
守护进程
守护进程会随着守护的进程结束而立刻结束
eg: A是B的守护进程 一旦B嗝屁了 A立刻嗝屁
from multiprocessing import Process
import time
def task(name):
print('德邦总管: %s' % name)
time.sleep(2)
print('德邦总管: %s' % name)
if __name__ == '__main__':
p1 = Process(target=task, args=('B',))
p1.daemon = True
p1.start()
time.sleep(1)
print('恕瑞玛皇帝: A嗝屁了')
僵尸进程与孤儿进程
僵尸进程
进程执行完毕后并不会立刻销毁所有的数据 会有一些信息短暂保留下来
比如进程号、进程执行时间、进程消耗功率等给父进程查看
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.randrange(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(1,11):
p = Process(target=run, args=('用户%s' % i,))
p.start()
"""
多进程操作数据很肯会造成数据错乱>>>:互斥锁
互斥锁
将并发变成串行 牺牲了效率但是保障了数据的安全
"""
# 加锁之后的代码
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:
with open(r'data.json', 'w',encoding='utf8')as f:
data['ticket_num'] -= 1
json.dump(data,f)
print('%s 买票成功' % name)
else:
print('%s 买票失败 非常可乐 没车回去了'% 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=('用户%s号' % i,mutex))
p.start()
"""
锁有很多种 但是作用都一样
行锁 表锁。。。。
"""
python31 网络并发编程方法的更多相关文章
- 2、网络并发编程--套接字编程、黏包问题、struct模块、制作简易报头、上传文件数据
昨日内容回顾 面向对象复习(json序列化类) 对象.类.父类的概念 三大特性:封装 继承 多态 双下开头的方法(达到某个条件自动触发) __init__:对象实例化自动触发 __str__:对象执行 ...
- 1、网络并发编程--简介、软件开发架构、OSI七层协议
python复习 变量与常量 基本数据类型 内置方法 字符编码.文件操作 函数 函数参数.闭包函数.装饰器 面向对象 封装.继承.多态 """ 什么是对象 数据与功能的结 ...
- 3、网络并发编程--udp代码、操作系统发展史、多道技术、进程理论
昨日内容回顾 socket基本使用 # 内置的模块 import socket s = socket.socket() # 默认是TCP协议 也可以切换为UDP协议 s.bind((ip,port)) ...
- python之路32 网络并发线程方法 线程池 协程
多进程实现TCP服务端并发 服务端: import socket from multiprocessing import Process def get_server(): server = sock ...
- 4、网络并发编程--僵尸进程、孤儿进程、守护进程、互斥锁、消息队列、IPC机制、生产者消费者模型、线程理论与实操
昨日内容回顾 操作系统发展史 1.穿孔卡片 CPU利用率极低 2.联机批处理系统 CPU效率有所提升 3.脱机批处理系统 CPU效率极大提升(现代计算机雏形) 多道技术(单核CPU) 串行:多个任务依 ...
- 【转】高性能网络编程5--IO复用与并发编程
对于服务器的并发处理能力,我们需要的是:每一毫秒服务器都能及时处理这一毫秒内收到的数百个不同TCP连接上的报文,与此同时,可能服务器上还有数以十万计的最近几秒没有收发任何报文的相对不活跃连接.同时处理 ...
- 03并发编程(多道技术+进程理论+进程join方法)
目录 03 并发编程 03 并发编程
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之三unlock方法分析
前篇博客LZ已经分析了ReentrantLock的lock()实现过程,我们了解到lock实现机制有公平锁和非公平锁,两者的主要区别在于公平锁要按照CLH队列等待获取锁,而非公平锁无视CLH队列直接获 ...
- Java并发编程(一) 两种实现多线程的方法(Thread,Runnable)
Java中实现多线程的方法有两种: 继承Thread类和实现Runnable方法,并重写Run方法,然后调用start()方法启动线程.使用Runnable会比Thread要好很多,主要是以下三个原因 ...
随机推荐
- 分支结构之二:switch-case
1.格式 switch(表达式){case 常量1: 执行语句1; //break; case 常量2: 执行语句2; //break; ... default: 执行语句n; //break; } ...
- SpringBoot→Maven项目快速搭建
使用软件 :SpringToolSuite4 打开软件后在Package Explorer 栏中点击右键 Spring starter project 等待反应 填写完毕之后点击next fi ...
- 浅尝 ECDHE 协议流程
前言 ECDHE 我之前是听都没听过, 但是新业务需要对前后端通信进行加密, 经过大佬推荐才知道有这个东西, 经过几天的学习和踩坑, 才大致明白其流程和使用方式. 过程坎坷, 好在最后还是成功运用到了 ...
- FileNotFoundError: Could not find module libmxnet.dll
解决方法:把CUDA的bin目录下的dll文件全部复制到libmxnet.dll所在的目录 问题原因:libmxnet.dll引用了一些CUDA的dll,但是找不到路径.
- 只能用于文本与图像数据?No!看TabTransformer对结构化业务数据精准建模
作者:韩信子@ShowMeAI 深度学习实战系列:https://www.showmeai.tech/tutorials/42 TensorFlow 实战系列:https://www.showmeai ...
- Vue3 企业级优雅实战 - 组件库框架 - 4 组件库的 CSS 架构
在前一篇文章中分享了搭建组件库的基本开发环境.创建了 foo 组件模块和组件库入口模块,本文分享组件库的样式架构设计. 1 常见的 CSS 架构模式 常见的 CSS 架构模式有很多:OOCSS.ACS ...
- Gitlab 和 jenkins 搭建遇到的坑
1 Gitlab 端口默认 80 所有其他程序提前把端口腾空 2 Gitlab 配置的是pub 公钥 3 java版本要在1.8以上 4 Jenkins 配置私钥 5 需要配置各个目录的workspa ...
- [C# 中的序列化与反序列化](.NET 源码学习)
[C# 中的序列化与反序列化](.NET 源码学习) 关键词:序列化(概念与分析) 三种序列化(底层原理 源码) Stream(底层原理 源码) 反射(底层原理 源码) 假如有一天我 ...
- CPU TLB原理 [转载好文]
首先,我们知道MMU的作用是把虚拟地址转换成物理地址.虚拟地址和物理地址的映射关系存储在页表中,而现在页表又是分级的.64位系统常见的配置是4级页表,就以4级页表为例说明.分别是PGD.PUD.PMD ...
- 在链表上实现 Partition 以及荷兰国旗问题
在链表上实现 Partition 以及荷兰国旗问题 作者:Grey 原文地址: 博客园:在链表上实现 Partition 以及荷兰国旗问题 CSDN:在链表上实现 Partition 以及荷兰国旗问题 ...