124 并发编程小结
目录
- 一、到底什么是线程?什么是进程?
- 二、Python多线程情况下:
- 三、Python多进程的情况下:
- 四、为什么有这把GIL锁?
- 五、Python中线程和进程(GIL锁)
- 六、为什么要创建线程?
- 七、为什么要创建进程?
- 八、进程和线程的区别?
- 九、线程创建的越多越好吗?
- 十、生产者消费者模型解决了什么问题?
- 十一、Lock和RLock的区别?
- 十二、进程和线程以及协程的区别?
- 十三、IO多路复用作用?
- 十四、socket默认是否是阻塞的?阻塞体现在哪里?
- 十五、什么是异步非阻塞?
- 十六、什么是同步阻塞?
- 十七、什么是协程?
- 十八、协程可以提高并发吗?
- 十九、提高并发方案:
- 二十、单线程提供并发
- 20.1 基于IO多路复用+socket非阻塞
- 20.2 协程+IO切换:gevent
- 20.3 基于事件循环的异步
- 20.3.1 方法一
- 20.3.2 方法二
- 20.4 基于事件循环的异步非阻塞框架
一、到底什么是线程?什么是进程?
Python自己没有这玩意,Python中调用的操作系统的线程和进程。
二、Python多线程情况下:
计算密集型操作:效率低,Python内置的一个全局解释器锁,锁的作用就是保证同一时刻一个进程中只有一个线程可以被cpu调度,多线程无法利用多核优势,可以通过多进程方式解决,但是比较浪费资源。
IO操作:效率高
三、Python多进程的情况下:
计算密集型操作:效率高(浪费资源),不得已而为之。
IO操作:效率高(浪费资源)
四、为什么有这把GIL锁?
Python语言的创始人在开发这门语言时,目的快速把语言开发出来,如果加上GIL锁(C语言加锁),切换时按照100条字节指令来进行线程间的切换。
五、Python中线程和进程(GIL锁)
GIL锁,全局解释器锁。用于限制一个进程中同一时刻只有一个线程被cpu调度。
扩展:默认GIL锁在执行100个cpu指令(过期时间)。
查看GIL切换的指令个数
import sys
v1 = sys。getcheckinterval()
print(v1)
六、为什么要创建线程?
由于线程是cpu工作的最小单元,创建线程可以利用多核优势实现并行操作(Java/C#)。
注意:线程是为了工作。
七、为什么要创建进程?
进程和进程之间做数据隔离(Java/C#)。
注意:进程是为了提供环境让线程工作。
八、进程和线程的区别?
进程是资源分配的最小单位,线程是程序执行的最小单位。
进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段,堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程小很多,同时创建一个线程的开销比进程要小很多。
线程之间的通信更方便,同一进程下的线程共享全局变量,静态变量,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
也正是由于GIL锁的原因:IO密集型操作可以使用多线程,计算密集型可以使用多进程。
九、线程创建的越多越好吗?
不好。线程之间进行切换时,要做上下文管理。
十、生产者消费者模型解决了什么问题?
不用一直等待的问题。
十一、Lock和RLock的区别?
RLock可以多次加锁。
十二、进程和线程以及协程的区别?
进程是cpu资源分配的最小单元,一个进程中可以有多个线程。
线程是cpu计算的最小单元。
对于Python来说他的进程和线程和其他语言有差异,是有GIL锁。
GIL锁保证一个进程中同一时刻只有一个线程被cpu调度。
注意:IO密集型操作可以使用多线程,计算密集型可以使用多进程。
协程,是由程序员创造出来的一个不是真实存在的东西。
协程,是微线程,对一个线程进程分片,使得线程在代码块之间进行来回切换执行,而不是在原来逐行执行。
十三、IO多路复用作用?
检测多个socket是否已经发生变化(是否已经连接成功/是否已经获取数据)(可读/可写)IO多路复用作用?
检测多个socket是否发生变化。
操作系统检测socket是否发生变化,有三种模式:
- select:最多1024个socket;循环去检测。
- poll:不限制监听socket个数;循环去检测(水平触发)。
- epoll:不限制监听socket个数;回调方式(边缘触发)。
Python模块:
- select.select
- select.epoll
十四、socket默认是否是阻塞的?阻塞体现在哪里?
默认是阻塞,填在等待消息和连接
十五、什么是异步非阻塞?
非阻塞,不等待。比如创建socket对某个地址进行connect、获取接收数据recv时默认都会等待(连接成功或接收到数据),才执行后续操作。
如果设置setblocking(False),以上两个过程就不再等待,但是会报BlockingIOError的错误,只要捕获即可。
异步,通知,执行完成之后自动执行回调函数或自动执行某些操作(通知)。比如做爬虫中向某个地址baidu。com发送请求,当请求执行完成之后自执行回调函数。
十六、什么是同步阻塞?
- 阻塞:等
- 同步:按照顺序逐步执行
十七、什么是协程?
协程也可以称为“微线程”,就是开发者控制线程执行流程,控制先执行某段代码然后再切换到另外函执行代码...来回切换。
十八、协程可以提高并发吗?
协程自己本身无法实现并发(甚至性能会降低)。
协程+IO切换性能提高。
十九、提高并发方案:
- 多进程
- 多线程
- 单线程提供并发
二十、单线程提供并发
20.1 基于IO多路复用+socket非阻塞
实现并发请求(一个线程100个请求)
import socket
# 创建socket
client = socket.socket()
# 将原来阻塞的位置变成非阻塞(报错)
client.setblocking(False)# 百度创建连接: 阻塞
try:# 执行了但报错了client.connect(('www.baidu.com',80))
except BlockingIOError as e:pass# 检测到已经连接成功# 问百度我要什么?
client.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n')# 我等着接收百度给我的回复
chunk_list = []
while True:# 将原来阻塞的位置变成非阻塞(报错)chunk = client.recv(8096) if not chunk:breakchunk_list.append(chunk)body = b''.join(chunk_list)
print(body.decode('utf-8'))
20.2 协程+IO切换:gevent
from gevent import monkey
# 以后代码中遇到IO都会自动执行greenlet的switch进行切换
monkey.patch_all()
import requests
import geventdef get_page1(url):ret = requests.get(url)print(url,ret.content)def get_page2(url):ret = requests.get(url)print(url,ret.content)def get_page3(url):ret = requests.get(url)print(url,ret.content)gevent.joinall([gevent.spawn(get_page1, 'https://www.python.org/'), # 协程1gevent.spawn(get_page2, 'https://www.yahoo.com/'), # 协程2gevent.spawn(get_page3, 'https://github.com/'), # 协程3
])
20.3 基于事件循环的异步
执行完某个人物后自动调用我给他的函数,非阻塞
20.3.1 方法一
import socket
import select# 百度创建连接:非阻塞
client1 = socket.socket()
client1.setblocking(False)
try:client1.connect(('www.baidu.com', 80))
except BlockingIOError as e:pass# 搜狗创建连接:非阻塞
client2 = socket.socket()
client2.setblocking(False)
try:client2.connect(('www.sogou.com', 80))
except BlockingIOError as e:pass# GitHub创建连接:非阻塞
client3 = socket.socket()
client3.setblocking(False)
try:client3.connect(('www.github.com', 80))
except BlockingIOError as e:pass# 创建socket列表:socket_list
socket_list = [client1, client2, client3]
# 创建connect列表:conn_list
conn_list = [client1, client2, client3]while True:rlist, wlist, elist = select.select(socket_list, conn_list, [], 0.005)# rlist中表示已近获取数据的socket对象# wlist中表示已经连接成功的socket对象# elist中表示出现错误的socket对象for sk in wlist:if sk == client1:sk.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n')elif sk == client2:sk.sendall(b'GET /web?query=fdf HTTP/1.0\r\nhost:www.sogou.com\r\n\r\n')else:sk.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.oldboyedu.com\r\n\r\n')conn_list.remove(sk)for sk in rlist:chunk_list = []while True:try:chunk = sk.recv(8096)if not chunk:breakchunk_list.append(chunk)except BlockingIOError as e:breakbody = b''.join(chunk_list)# print(body.decode('utf-8'))print('------------>', body)sk.close()socket_list.remove(sk)if not socket_list:break
20.3.2 方法二
import socket
import selectclass Req(object):def __init__(self,sk,func):self.sock = skself.func = funcdef fileno(self):return self.sock.fileno()class Nb(object):def __init__(self):self.conn_list = []self.socket_list = []def add(self,url,func):# 创建socket客户端client = socket.socket()# 非阻塞client.setblocking(False)try:# 创建连接client.connect((url, 80))# 异常处理except BlockingIOError as e:passobj = Req(client,func)# 连接列表self.conn_list.append(obj)# socket列表self.socket_list.append(obj)def run(self):while True:rlist,wlist,elist = select.select(self.socket_list,self.conn_list,[],0.005)# wlist中表示已经连接成功的req对象for sk in wlist:# 发生变换的req对象sk.sock.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n')self.conn_list.remove(sk)for sk in rlist:chunk_list = []while True:try:chunk = sk.sock.recv(8096)if not chunk:breakchunk_list.append(chunk)except BlockingIOError as e:breakbody = b''.join(chunk_list)# print(body.decode('utf-8'))sk.func(body)sk.sock.close()self.socket_list.remove(sk)if not self.socket_list:breakdef baidu_repsonse(body):print('百度下载结果:',body)def sogou_repsonse(body):print('搜狗下载结果:', body)def github_repsonse(body):print('GITHUB下载结果:', body)t1 = Nb()
t1.add('www.baidu.com',baidu_repsonse)
t1.add('www.sogou.com',sogou_repsonse)
t1.add('www.github.com',oldboyedu_repsonse)
t1.run()
20.4 基于事件循环的异步非阻塞框架
如Twisted框架,scrapy框架(单线程完成并发)
转载于:https://www.cnblogs.com/XuChengNotes/p/11553390.html
124 并发编程小结相关推荐
- 《Java线程与并发编程实践》—— 2.6 小结
本节书摘来异步社区<Java线程与并发编程实践>一书中的第2章,第2.6节,作者: [美]Jeff Friesen,更多章节内容可以访问云栖社区"异步社区"公众号查看. ...
- Java并发编程实战————并发技巧小结
可变状态是至关重要的.所有的并发问题都可以归结为如何协调对并发状态的访问.可变状态越少,就越容易确保线程安全性. 尽量将域声明为final类型,除非需要它们是可变的. 不可变对象一定是线程安全的.不可 ...
- Java 并发编程的艺术 pdf 下载
并发编程领域的扛鼎之作,作者是阿里和1号店的资深Java技术专家,对并发编程有非常深入的研究,<Java并发编程的艺术>是他们多年一线开发经验的结晶.本书的部分内容在出版早期发表在Java ...
- 第二十四章 并发编程
第二十四章 并发编程 爱丽丝:"但是我不想进入疯狂的人群中" 猫咪:"oh,你无能为力,我们都疯了,我疯了,你也疯了" 爱丽丝:"你怎么知道我疯了&q ...
- 并发编程基础篇——第一章(并发相关基础概念理解)
其实讲到并发编程,有时候会问自己为什么要去做这些知识的积累和沉淀,可能我们做业务的在职业生涯里,并不会经常使用到这些所谓的多线程编程,顶多可能开一个线程,去执行个任务,又或者通过定时器触发某个业务,实 ...
- Java 高并发_JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过!...
JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过! 1.JPG (37.82 KB, 下载次数: 0) 2018-12-3 09:40 上传 2.JPG (28 ...
- Java Review - 并发编程_ 回环屏障CyclicBarrier原理源码剖析
文章目录 Pre 小Demo 类图结构 CyclicBarrier核心方法源码解读 int await() int await(long timeout, TimeUnit unit) int dow ...
- Java Review - 并发编程_ScheduledThreadPoolExecutor原理源码剖析
文章目录 概述 类结构 核心方法&源码解析 schedule(Runnable command, long delay,TimeUnit unit) scheduleWithFixedDela ...
- Java Review - 并发编程_ArrayBlockingQueue原理源码剖析
文章目录 概述 类图结构 构造函数 主要方法源码解析 offer操作 put操作 poll操作 take操作 peek操作 size 小结 概述 Java Review - 并发编程_LinkedBl ...
- Java Review - 并发编程_读写锁ReentrantReadWriteLock的原理源码剖析
文章目录 ReentrantLock VS ReentrantReadWriteLock 类图结构 非公平的读写锁实现 写锁的获取与释放 void lock() void lockInterrupti ...
最新文章
- 小撒、金晨都想拥有!百度全球首款汽车机器人亮相,车内躺着看星星
- linux备忘录-vi和vim
- 解决oh my zsh Insecure completion-dependent directories detected
- 基本数据类型与String之间的转换
- 前端学习(590):调试javascript的流程
- java menu单击事件_TinyMCE自定义工具栏menuItem单击触发所有父项的单击事件
- linux实验报告一,linux实验报告
- Leetcode每日一题:37.sudoku-solver(解数独)
- Docker删除/停止容器
- 如何才能快速匹配到大号?
- 【Shell】按行读取文件内容
- 云服务器微信faq,开发者FAQ
- java ftps 证书_java – 连接到FTPS服务器
- 当下移动互联网的6个泡沫,快要破了!
- ie窗口如何最大化设置
- php格林威治时间,PHP默认时间是格林威治时间。
- codeception apiTest入门
- 浅析分布式数据库同步技术理论
- “数智话”技术沙龙 第四期 | 弹性MapReduce(EMR)专场内容回顾!
- 解决 Client.Timeout exceeded while awaiting headers或Docker Pulling fs layer net/http: TLS handshake的方案
热门文章
- python超市管理系统总汇总功能解说_AdminModules --- 管理模块
- android其他占用存储,Android如何梳理内存占用情况解决OOM问题
- 基于SSM的健身俱乐部管理系统
- 实现Oracle查询用户所有表
- 算法,PHP取数据库中百万条数据中随机20条记录
- Spring boot 2.x 错误处理机制 与 定制错误页面
- 阶段3 1.Mybatis_12.Mybatis注解开发_5 mybatis注解建立实体类属性和数据库表中列的对应关系...
- Java8新特性:接口
- 有目标就有动力!有目标就有意义!
- 【BZOJ 3681】Arietta