1.操作系统帮助开发者操作硬件
2.程序员写好代码在操作系统上运行(依赖解释器)
线程的基本使用
def func(arg):
print(arg)
t = threading.Thread(target=func,args=(11,))
t.start() 开始就绪
print(111)
主线程默认等子线程执行完毕
t = threading.Thread(target=func,args=(11,))
t.setDaemon(True)
t.start() 主线程不再等子线程,主线程终止则所有线程终止
join() 开发者可以控制主线程等待子线程(最多等待时间)
t.start()
t.join() 主线程等着,等到子线程执行完毕,才可以继续往下走
t.join(2) 子线程最多等两秒
lock = threading.RLock()
lock.acquire() 加锁,此区域的代码同一时刻只能有一个线程执行
lock.release() 释放锁
Python 的 GIL锁
python内置的一个全局解释器锁,锁的作用就是保证同一时刻一个进程中只有一个线程可以被CPU调度
为什么有这把GIL锁
Python语言的创始人在开发这门语言是,目的快速把语言开发出来,如果加上GIL锁,切换时按照100条字节指令来进行线程间的切换(编写起来简单)
为什么要加GIL锁 为了线程安全
非线程安全
控制一段代码
进程和线程的区别
线程是CPU工作的最小单元
进程为线程提供一个资源共享的空间 /是CPU资源分配的最小单元
一个进程中可以有多个线程
对于python来说它的进程和线程和其他语言有差异,是GIL锁,GIL锁保证一个进程中同一时刻只有线程被CPU调度
IO操作不占用CPU
进程和线程的使用准则
计算密集型:多进程
IO密集型:多线程
锁:Lock 一次锁
线程安全,多线程操作时,内部会让所有线程排队处理
RLock 支持多锁锁解(一次放一个)递归锁
lock = threading.BoudedSemaphore(一次放N个) 信号量
Condition(一次放x个,动态的)
Event(一次放所有)
ct = threading.current_thread() 获取当前线程
ct.getName() 获取名字
线程池
只有python3中有
threading,local 为每一个线程开辟空间,存取数据
import multiprocessing
multiprocessing.Queue() 进程间数据共享
进程池/线程池
import time
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
def task(arg):
time.sleep(2)
print(arg)
pool = ThreadPoolExeccutor(5) 限制一次五个线程#线程:ProcessPoolExecutor(5) Windows需要加上 if __name__ == '__main__':
for i in range(10) 进程建议几核就几个进程
pool.submit(task,i)
IO多路复用
I Input O Output IO多路复用可以监听所有的IO请求的状态。socket,cmd终端
作用:检测多个socket是否已经发生变化(是否连接成功/是否已经获取获取数据)(可读/可写)
操作系统检测socket是否发生变化有三种模式:
select:最多监听1024个socket;循环去检测
poll:不限制监听socket个数;循环去检测(水平触发)
epoll:不限制监听socket个数;回调方式(边缘触发)
基于IO多路复用+socket实现并发请求(一个线程100个请求)
用到的:IO多路复用 + socket非阻塞
client.setblocking(False) #非阻塞
基于事件循环实现的异步非阻塞框架
非阻塞:不等待 比如:创建socket对某个地址进行connect,获取接收数据recv时默认都会等待,连接成功后或接受到数据时,才会执行后续操作,如果设置setblocking(False),以上两个过程就不在等待,但是会报BlockingIOError的错误,只要捕获即可
异步:执行完某个任务后,自动执行回调函数或自动执行某些操作(通知) 比如:做爬虫中向某个地址baidu.com发送请求,当请求执行完成之后自动执行回调函数
同步阻塞
阻塞:等
同步:按照顺序逐步执行
已经实现的模块:Twisted 基于事件循环实现的异步非阻塞框架
提高并发的方案:
多进程
多线程
异步非阻塞模块(Twisted) scrapy框架(单线程完成并发)
协程 greenlet
协程是微线程,对一个线程进行分片,使得线程在代码块之间进行来回切换,而不是逐步执行
import greenlet
def f1():
print(11)
gr2.switch()
print(22)
gr2.switch()
def f2():
print(33)
gr1.switch()
print(44)
gr1 = greenlet.greenlet(f1)
gr2 = greenlet.greenlet(f2)
gr1.switch()
哈哈
单纯的协程无用
协程 + 遇到IO就切换 pip3 install gevent
from gevent import monkey
monkey.patch_all()
import requests
import gevent
def get_page(url):
ret = requests.get(url)
print(url,ret.content)
gevent.joinall([
gevent.spawn(get_page,'https://www.python.org/'),#协程
gevent.spawn(get_page,'https://www.yahoo.com/'),#协程
gevent.spawn(get_page,'https://github.com/')#协程
])
haha
1.什么是协程?
协程也可以成为“微线程”,就是开发者控制线程执行流程,控制先执行某段代码然后在切换到另外函数执行代码。。。来回切换
遇到switch就切换
2.协程可以提高并发吗?
协程自己本身无法实现并发(甚至性能会降低)
协程 + IO切换 性能提高
3.进程,线程,协程 的区别?
4.单线程提供并发:
协程 + IO切换:gevent
基于时间循环的异步非阻塞框架:Twisted