Day 37 协程相关

Day 37

一、线程池和进程池的shutdown

self.shutdown(wait=True)

​ 等待所有线/进程任务完成,并且把池关闭,再执行主进程的内容。一般放在for循环外面,需要注意的是,关闭线/进程池之后,就不能再提交任务了。再执行主进程的内容

  • wait=True,等待池内所有任务执行完毕回收完资源后才继续

  • wait=False,立即返回,并不会等待池内的任务执行完毕

  • 但不管wait参数为何值,整个程序都会等到所有任务执行完毕

  • submit和map必须在shutdown之前

    import time
    from concurrent.futures import ThreadPoolExecutor
    
    pool = ThreadPoolExecutor(3)
    
    
    def task():
        print("我要开始了......")
        time.sleep(2)
        print("我结束了....")
    
    
    def call_back(f):
        pass
    
    
    if __name__ == '__main__':
        for i in range(10):
            pool.submit(task).add_done_callback(call_back)
    
        pool.shutdown(wait=True)
        # pool.submit(task).add_done_callback(call_back)
        # cannot schedule new futures after shutdown
        print("主进程结束!")
        
    ---------------------------
    >>> 我要开始了......
    >>> 我要开始了......
    >>> 我要开始了......
    >>> ....
    >>> 主进程结束!
    

二、定时器

class Timer(Thread):

Timer(定时器)是Thread的派生类,用于在指定时间后调用一个方法。Timer从Thread派生,没有增加实例方法。

  • t = Timer(30.0, f, args=None, kwargs=None) 基本使用
  • t.start() 开始
  • t.cancel() 如果计时器仍在等待,则停止它的动作
from threading import Timer, current_thread


def print_data(name):
    print(f"{name} 在玩《黑神话·悟空》!")
    print(f"我是线程{current_thread().getName()}")


if __name__ == '__main__':
    for i in range(10):
        p = Timer(2, print_data, kwargs={"name": "毛成"})
        p.start()
-------------------------------------
>>> 毛成 在玩《黑神话·悟空》!
	我是线程Thread-1
    ........
>>> 毛成 在玩《黑神话·悟空》!
	我是线程Thread-10

三、协程介绍

协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。

协程是为了实现单线程下的并发,属性线程下

协程要解决的问题:保存状态+切换

yield:生成器,只要函数中有yield关键字,这个函数就是生成器,通过yield可以实现 保存状态+切换

优点:

  • 协程的切换开销更小,属于程序级别的切换,操作系统感知不到,因而更加轻量级
  • 单线程内就可以实现并发的效果,最大限度的利用CPU

缺点:

  • 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程开启协程
  • 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程

特点:

必须在只有一个单线程里实现并发

修改共享数据不需要加锁

用户程序里自己保存多个控制流的上下文栈(需要保存的状态)

附加:一个协程遇到IO操作自动切换到其他协程(如何实现检测IO,yield,greenlet都无法实现,就要用到gevent模块(select机制))

四、greetlet模块

switch 将执行切换到此greenlet

from greenlet import greenlet
import time


def eat():
    print("我吃了一口!")
    time.sleep(1)
    p.switch()  # 2. 切换到play print("我玩了一会儿!")
    print("我又吃了一口!")
    p.switch()  # 4. 切换到play print("我又玩了一会儿!")


def play():
    print("我玩了一会儿!")
    e.switch()  # 3.切换到 eat print("我又吃了一口!")
    time.sleep(1)
    print("我又玩了一会儿!")


if __name__ == '__main__':
    e = greenlet(eat)
    p = greenlet(play)
    e.switch()  # 1. 切换到eat print("我吃了一口!")
-----------------------------------
>>> 我吃了一口!
>>> 我玩了一会儿!
>>> 我又吃了一口!
>>> 我又玩了一会儿!

五、gevent

  • gevent是在greenlet的基础上进行封装使得gevent变得更加的易用。
  • gevent采用了隐式启动事件循环,即在需要阻塞的时候开启一个专门的协程来启动事件循环;
  • 如果一个任务没有io操作,那么他会一直执行直到完成;其他协程没有执行的机会;
  • 自动识别io事件,放弃CPU控制时间

使用方法

  • gevent.spawn():创建一个普通的Greenlet对象并切换;

  • # 不常用
    - gevent.spawn_later(seconds=3) # 延时创建一个普通的Greenlet对象并切换 
    - gevent.spawn_raw() # 创建的协程对象属于一个组
    - gevent.getcurrent() # 返回当前正在执行的
    - greenlet gevent.joinall(jobs):将协程任务添加到事件循环,接收一个任务列表
    - gevent.wait() # 可以替代join函数等待循环结束,也可以传入协程对象列表、 、
    - gevent.kill() # 杀死一个协程
    - gevent.killall() # 杀死一个协程列表里的所有协程 
    
  • monkey.patch_all():非常重要,会自动将python的一些标准模块替换成gevent框架

import gevent
import time
from gevent import monkey;monkey.patch_all()  # 类似猴子补丁


def eat():
    print("我吃了一口!")
    time.sleep(1)
    print("我又吃了一口!")


def play(name):
    print(f"{name}玩了一会儿!")
    time.sleep(2)
    print(f"{name}又玩了一会儿!")


if __name__ == '__main__':
    e = gevent.spawn(eat)
    p = gevent.spawn(play, "川普")
    e.join()  #固定用法  如果不用 遇到IO操作会退出
    p.join()

六、asyncio

# 官方支持协程的库



# import time
# import asyncio
#
# # 把普通函数变成协程函数
# # 3.5以前这么写
# @asyncio.coroutine
# def task():
#     print('开始了')
#     yield from asyncio.sleep(1)  #asyncio.sleep(1)模拟io
#     print('结束了')
#
#
# loop=asyncio.get_event_loop()  # 获取一个时间循环对象#
#
# # 协程函数加括号,并不会真正的去执行,它需要提交给loop,让loop循环着去执行
# # 协程函数列表
#
# ctime=time.time()
# t=[task(),task()]
# loop.run_until_complete(asyncio.wait(t))
# loop.close()
# print(time.time()-ctime)


import time
import asyncio
from threading import current_thread
# 表示我是协程函数,等同于3.5之前的装饰器
async def task():
    print('开始了')
    print(current_thread().name)
    await asyncio.sleep(3)  # await等同于原来的yield from
    print('结束了')

async def task2():
    print('开始了')
    print(current_thread().name)
    await asyncio.sleep(2)
    print('结束了')

loop=asyncio.get_event_loop()

ctime=time.time()
t=[task(),task2()]
loop.run_until_complete(asyncio.wait(t))
loop.close()
print(time.time()-ctime)

7 io模型(重点,抽象,难,面试重点)

1 内存分为内核缓冲区和用户缓冲区(网络下载的资源,硬盘加载的资源,先放到内核缓冲区----》copy到应用程序的缓冲区,应用程序才能用这个数据)

2 io模型:
	-阻塞io(BIO)
    -非阻塞io(NIO)
    -io多路复用()  select(windows支持,windows不支持epoll,官方不提供redis的window版本),poll,epoll(linux支持)
    -异步io:
    -信号驱动io(理论,不在考虑范围内)

补充虚拟环境

1 解决不同项目依赖的模块版本不同的问题
2 pycharm中创建项目时选择
	-这个虚拟环境可不可以给其他项目使用(取决你是否选择)
    -基于系统解释器当前状态还是纯净状态来创建虚拟环境
3 装模块:
	-cmd窗口下:pip3 install flask   (装在谁下,你一定要确认好)
    -推荐你们用pycharm:setting---》那一套
    -pycharm下的terminal下装(相当于cmd),比cmd好在,它有个提示
4 现在用了虚拟环境如何换到系统环境
    
4 环境变量的作用
	-把一个路径加入到环境变量,以后该路径下的命令,可以再任意位置执行
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值