(1)线程池和进程池的shutdown
(2)定时器Timer
(3)协程
(4)虚拟环境
(5)greenlet模块
(6)gevent模块
(7)asyncio模块
(8)IO模型
# 线程池shutdown
'''
from concurrent.futures import ThreadPoolExecutor
import time
pool = ThreadPoolExecutor(3)
def task(name):
print(f'{name}begin...')
time.sleep(2)
print(f'{name}end...')
if __name__ == '__main__':
for i in range(10):
pool.submit(task, i)
pool.shutdown(wait=True) # 等待所有任务执行完成,并关闭线程池,不能再继续提交任务
print('main......')
'''
# 定时器Timer
'''
from threading import Timer
def task(name):
print(f'{name} is sb.')
if __name__ == '__main__':
# t = Timer(2, task, args=('lh',)) # 本质是开启一个线程,延迟2s后执行
t = Timer(2, task, kwargs={'name': 'lh'})
t.start()
'''
# 协程
'''
# 协程是为了实现单线程下的并发,属于线程之下,解决的问题:保存状态+切换
# 协程是一个抽象的概念,实际并不存在。由程序员来控制,不让程序遇到IO,看上去就是实现并发
# import time
#
#
# def func1():
# for i in range(10000000):
# i += 1
#
#
# def func2():
# for i in range(10000000):
# i += 1
#
#
# if __name__ == '__main__':
# ctime = time.time()
# func1()
# func2()
# print(time.time() - ctime) # 1.0483405590057373
# 通过yield实现保存状态+切换,(自定义的切换,并不是遇到IO才切换,所以不能节约时间)
# 单纯的切换不但不能提高效率,反而会降低效率
# import time
#
#
# def func1():
# for i in range(10000000):
# i += 1
# yield
#
#
# def func2():
# g = func1()
# for i in range(10000000):
# i += 1
# next(g)
#
#
# if __name__ == '__main__':
# ctime = time.time()
# # func1()
# func2()
# print(time.time() - ctime) # 2.008742094039917
# 优点:
# (1)协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
# (2)单线程内就可以实现并发的效果,最大限度地利用cpu
# 缺点:
# (1)协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程
# (2)协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程
# 总结协程特点:
# (1)必须在只有一个单线程里实现并发
# (2)修改共享数据不需加锁
# (3)用户程序里自己保存多个控制流的上下文栈(需要保存状态)
# 附加:一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))
'''
# 虚拟环境
'''
# 1、解决不同项目依赖的模块版本不同的问题
# 2、pycharm中创建项目时选择
# -基于系统解释器当前状态或纯净状态来创建虚拟环境
# -这个虚拟环境是否可以给其他项目使用
# 3、装模块:
# -cmd窗口下:pip3 install ...
# -推荐用pycharm:setting
# -pycharm下的terminal下装(相当于cmd)
# 4、环境变量的作用
# -把一个路径加入到环境变量,以后该路径下的命令,可以在任意位置执行
'''
# greenlet模块
'''
# 初级模块,遇到IO不会切换;基于greenlet有了gevent模块,处理IO切换
import time
from greenlet import greenlet
def taskA():
print('A one')
# time.sleep(1)
b.switch()
print('A two')
b.switch()
def taskB():
print('B one')
a.switch()
print('B two')
if __name__ == '__main__':
a = greenlet(taskA)
b = greenlet(taskB)
a.switch()
'''
# gevent模块
'''
# 基于greenlet写的,遇到IO自动切换
import time
import gevent
def taskA(name):
print(f'A one {name}')
gevent.sleep(1) # IO操作 自动切换
print(f'A two {name}')
def taskB(name):
print(f'B one {name}')
gevent.sleep(2)
print(f'B two {name}')
if __name__ == '__main__':
ctime = time.time()
a = gevent.spawn(taskA, 'lh')
b = gevent.spawn(taskB, 'lh')
a.join()
b.join()
print(time.time() - ctime) # 2.053565263748169
# ctime = time.time()
# taskA('lh')
# taskB('lh')
# a.join()
# b.join()
# print(time.time() - ctime) # 3.0617334842681885
# 猴子补丁
import time
import gevent
from gevent import monkey
monkey.patch_all() # 全部补丁
def taskA(name):
print(f'A one {name}')
time.sleep(1) # 被猴子补丁替换后,gevent.sleep(1)
print(f'A two {name}')
def taskB(name):
print(f'B one {name}')
time.sleep(2) # gevent.sleep(2)
print(f'B two {name}')
if __name__ == '__main__':
ctime = time.time()
a = gevent.spawn(taskA, 'lh')
b = gevent.spawn(taskB, 'lh')
a.join()
b.join()
print(time.time() - ctime) # 2.0102903842926025
'''
# asyncio模块
'''
# 官方支持协程的库
import asyncio
import time
# @asyncio.coroutine # python3.5以前的使用方法
# def task():
# print('begin...')
# yield from asyncio.sleep(1) # asyncio.sleep(1) 模拟IO
# print('end...')
#
#
# # print(task()) # <generator object task at 0x000001E7CB27BF90> (生成器)
# loop = asyncio.get_event_loop() # 创建一个事件循环对象
# t = [task(), task()] # 协程函数加括号,并不会真正执行,它需要提交给loop,让loop循环着执行
# ctime = time.time()
# loop.run_until_complete(asyncio.wait(t))
# loop.close()
# print(time.time() - ctime)
# python3.5之后的方法
async def task():
print('begin...')
await asyncio.sleep(1)
print('end...')
# print(task()) # <coroutine object task at 0x000001A3D464F0C0>
loop = asyncio.get_event_loop()
t = [task(), task()]
ctime = time.time()
loop.run_until_complete(asyncio.wait(t))
loop.close()
print(time.time() - ctime)
'''
# IO模型
# http://liuqingzheng.top/python/Python%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/25-IO%E6%A8%A1%E5%9E%8B/
1 内存分为内核缓冲区和用户缓冲区(网络下载的资源,硬盘加载的资源,先放到内核缓冲区----》copy到应用程序的缓冲区,应用程序才能用这个数据)
2 io模型:
-阻塞io(BIO)
-非阻塞io(NIO)
-io多路复用() select(windows支持,windows不支持epoll,官方不提供redis的window版本),poll,epoll(linux支持)
-异步io:
-信号驱动io(理论,不在考虑范围内)