目录

  • 一、到底什么是线程?什么是进程?
  • 二、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 并发编程小结相关推荐

  1. 《Java线程与并发编程实践》—— 2.6 小结

    本节书摘来异步社区<Java线程与并发编程实践>一书中的第2章,第2.6节,作者: [美]Jeff Friesen,更多章节内容可以访问云栖社区"异步社区"公众号查看. ...

  2. Java并发编程实战————并发技巧小结

    可变状态是至关重要的.所有的并发问题都可以归结为如何协调对并发状态的访问.可变状态越少,就越容易确保线程安全性. 尽量将域声明为final类型,除非需要它们是可变的. 不可变对象一定是线程安全的.不可 ...

  3. Java 并发编程的艺术 pdf 下载

    并发编程领域的扛鼎之作,作者是阿里和1号店的资深Java技术专家,对并发编程有非常深入的研究,<Java并发编程的艺术>是他们多年一线开发经验的结晶.本书的部分内容在出版早期发表在Java ...

  4. 第二十四章 并发编程

    第二十四章 并发编程 爱丽丝:"但是我不想进入疯狂的人群中" 猫咪:"oh,你无能为力,我们都疯了,我疯了,你也疯了" 爱丽丝:"你怎么知道我疯了&q ...

  5. 并发编程基础篇——第一章(并发相关基础概念理解)

    其实讲到并发编程,有时候会问自己为什么要去做这些知识的积累和沉淀,可能我们做业务的在职业生涯里,并不会经常使用到这些所谓的多线程编程,顶多可能开一个线程,去执行个任务,又或者通过定时器触发某个业务,实 ...

  6. Java 高并发_JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过!...

    JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过! 1.JPG (37.82 KB, 下载次数: 0) 2018-12-3 09:40 上传 2.JPG (28 ...

  7. Java Review - 并发编程_ 回环屏障CyclicBarrier原理源码剖析

    文章目录 Pre 小Demo 类图结构 CyclicBarrier核心方法源码解读 int await() int await(long timeout, TimeUnit unit) int dow ...

  8. Java Review - 并发编程_ScheduledThreadPoolExecutor原理源码剖析

    文章目录 概述 类结构 核心方法&源码解析 schedule(Runnable command, long delay,TimeUnit unit) scheduleWithFixedDela ...

  9. Java Review - 并发编程_ArrayBlockingQueue原理源码剖析

    文章目录 概述 类图结构 构造函数 主要方法源码解析 offer操作 put操作 poll操作 take操作 peek操作 size 小结 概述 Java Review - 并发编程_LinkedBl ...

  10. Java Review - 并发编程_读写锁ReentrantReadWriteLock的原理源码剖析

    文章目录 ReentrantLock VS ReentrantReadWriteLock 类图结构 非公平的读写锁实现 写锁的获取与释放 void lock() void lockInterrupti ...

最新文章

  1. 小撒、金晨都想拥有!百度全球首款汽车机器人亮相,车内躺着看星星
  2. linux备忘录-vi和vim
  3. 解决oh my zsh Insecure completion-dependent directories detected
  4. 基本数据类型与String之间的转换
  5. 前端学习(590):调试javascript的流程
  6. java menu单击事件_TinyMCE自定义工具栏menuItem单击触发所有父项的单击事件
  7. linux实验报告一,linux实验报告
  8. Leetcode每日一题:37.sudoku-solver(解数独)
  9. Docker删除/停止容器
  10. 如何才能快速匹配到大号?
  11. 【Shell】按行读取文件内容
  12. 云服务器微信faq,开发者FAQ
  13. java ftps 证书_java – 连接到FTPS服务器
  14. 当下移动互联网的6个泡沫,快要破了!
  15. ie窗口如何最大化设置
  16. php格林威治时间,PHP默认时间是格林威治时间。
  17. codeception apiTest入门
  18. 浅析分布式数据库同步技术理论
  19. “数智话”技术沙龙 第四期 | 弹性MapReduce(EMR)专场内容回顾!
  20. 解决 Client.Timeout exceeded while awaiting headers或Docker Pulling fs layer net/http: TLS handshake的方案

热门文章

  1. python超市管理系统总汇总功能解说_AdminModules --- 管理模块
  2. android其他占用存储,Android如何梳理内存占用情况解决OOM问题
  3. 基于SSM的健身俱乐部管理系统
  4. 实现Oracle查询用户所有表
  5. 算法,PHP取数据库中百万条数据中随机20条记录
  6. Spring boot 2.x 错误处理机制 与 定制错误页面
  7. 阶段3 1.Mybatis_12.Mybatis注解开发_5 mybatis注解建立实体类属性和数据库表中列的对应关系...
  8. Java8新特性:接口
  9. 有目标就有动力!有目标就有意义!
  10. 【BZOJ 3681】Arietta