多并发编程
并发:程序中的AB两个部分,通过A与B轮流切换,让外界感觉是一个进程
并行:程序中多个部分同时执行,需要计算机有多核或多个CPU
进程:启动一个程序,就启动了一个或多个进程,它是分配内存的最小基本单位
线程:一个进程包含一个或多个线程,它是比进程更小的单元,是CPU分配资源的基本单位
异步编程(I/O):一个线程里面包含多个协作式并发的子程序,又名为微线程
多线程/多进程
- from threading import Thread 导入多线程模块 / multiprocessing import Process 多进程 任务1=Thread(target=指派任务/函数,args=这个函数需要的参数–(元组,)一定传元组,一元组要加,号) 任务1.start() 启动这个线程任务,任务1.join() 占位,等任务结束才会停止start与join要分开,先线程全打开,再等他们都结束 进程使用与线程一样,只需要将Thread变成Process
如:要使用多线程保存图片时,循环打开下载图片连接Thread(target=保存函数,args=url).start()
更优雅的操作:t=Thread(ta…,arg…) 创建好后,将这个对象添加到列表里保存,再列表.start()
- threading.current_thread()可以获取当正在执行线程,打印或return —> .name 可以返回或展示当前线程的名字 当然,如果需要给线程指定名字,可以在创建线程任务时指定name=属性
缺点:频繁创建释放线程,额外开销较大 优点:即用即释放,时间换空间
线程池技术(实现对线程对象的重复利用,空间换时间)/进程池
- pool = ThreadPoolExecutor(max_workers=8)创建线程池对象,指定线程数量,pool.submit(函数,函数的参数)将任务交给线程池执行,用完线程池需要关闭线程池,pool.shutdown() 也可以使用上下文语法,with *** as pool: 可以不用关闭线程,离开上下文,自动关闭 线程池的submit可以返回一个future将来时对象,如果要等线程结束拿结果,或对其计时,可以将这个任务用变量保存,再放置到列表中,放完后遍历列表,对其.result()等待其结束,或拿到函数运行完成后的返回值 在代码层面上,进程池和线程池的使用都差不多,只是创建对象时名字变一下ProcessPoolExecutor()
注意: 记得关注我哦!
- 输出/入缓存区:内容在输出或输入时,会产生IO中断,cpu会停下来,操作系统为了提高cpu的利用率,会将要输入/出的内容放到输出/入缓存区,等到缓存区满或者用户加了结束操作(空格,回车之类的)以后,才会进行输入/出操作
守护线程
- 在创建线程对象指派任务后,添加daemon=True参数,可以将该线程创建为守护线程,主线程一停,守护线程自动关闭
自定义线程
- 重新写一个类,它继承Thread,我的父类是多线程,那我也是多线线程class NewThread(Thread): 定义类初始化方法,super().__init__() ,或者 super(NewThread,self).__init__() ,再重写run方法(不建议使用)
总结:多线程线程之间共享进程内的内存,通信方便,多进程之间相对独立,如果想要互相协调进程间的行为,要引用IPC机制(管道,套接字,共享存储区)
临界资源与锁机制(GIL全局解释器锁)
当多个线程竞争的一个资源叫临界资源,需要对其进行加锁保护,创建对象RLock(),获得锁Lock.acquire(),释放锁lock.release() ,当然可以使用上下文语法with 锁:这样进入上下文语法,自动加锁,离开自动释放
- 由于Cpython基于C语言写的,在申请malloc()和释放内存free()的时候并不能做到线程安全,程序很有可以崩溃,我们除了自己加锁外,它本身也引入了GIL全局解释器锁 加锁带来的后果为:无法利用CPU的多核特性 I/O密集型任务(不需要太多CPU,读写文件输入输出这些I/O密集型任务适合多线程,它不需要多核特性) 计算密集型任务(处理文件,压缩文件,作渲染等计算量大的任务,适合使用多进程,如果使用多进程,相当于每个进程就是一个python解释器环境,每个进程都有全局解释器锁,他们各干各的,放到各个核里去跑,可以充分发挥多核特性)
异步I/O:asyncio库
- 简介: BIO -阻塞式IO,一个IO操作在进行时,必须等待其结束,才能进行下一个IO操作,还没结束之前,无法操作 NIO -非阻塞式IO,多个I/O可以多路操作,但不能继续其他操作,会在这里轮流观察哪个操作完成了 AIO -异步I/O回调式I/O,多路操作,可以继续做别的任务,等I/O操作完成了,系统自动回调函数,继续执行这个操作任务的下一步行为
- 实现方式: 协程实现异步编程,创建可以相互协作的子程序(协程):它没有启用多线程多进程,它在一个线程里有多个可以互相协作的子程序,谁发生了I/O中断,就把CPU让给其他子程序,高效的利用了CPU,营造了并发的效果 异步函数具体操作: 1.笨方法:首先利用yield创建生成器子程序,在需要调用这个子程序时:将生成器预激活升级为协程—>先调这个生成器(创建生成器对象),然后用这个生成器对象.send(None)给生成器发一个空值过去(或者直接next(生成器对象)让next调一下),就完成了预激活,将这个子程序挂载到了主程序上,主程序运行的过程中,子程序发生等待时,不影响主程序的继续运行,他们相互配合就可以实现异步操作 2.推荐方法:将需要等待的部分写好后,def前加async 这样就将函数变成了协程对象的生成器函数,我们通过调用创建好协程对象以后将其用列表装好,由于协程对象要使用必须挂载到事件循环上才能使用, loop = asyncio.get_event_loop()这个事件循环是系统控制的事件循环,我们直接调用这个事件循环,然后用loop事件循环.run_until_complete(asyncio.wait(协程对象列表))就将其挂载到事件循环上运行了(wait方法可以将列表转换成任务对象,如果直接给协程对象,那就可以直接将其变成task任务对象),用完事件循环记得关闭loop.close() 利用异步函数获取页面响应内容—->使用aiohttp简单来异步获取网页响应内容 创建async 函数异步获得页面响应
async def main(): async with aiohttp.ClientSession() as session: #创建异步上下文的会话 async with session.get(端口) as response: #异步上下文会话打开网页 html = await response.content() # 由于获得网页响应的时候,会有阻塞和等待,使用await 关键字,让程序在发生阻塞和等待的时候,将cpu让给下一项任务 loop = asyncio.get_event_loop() # 创建事件循环对象 loop.run_until_complete(main()) # 将任务放到事件循环上运行
总结:进程切换开销>线程切换开销>协程(微线程)协程在一个线程里的切换操作,几乎没有开销
python关键字:assert()断言语句暂时用不到,as别名,async/await
break/continue退出/跳下一轮循环,class/def定义函数/类,del删引用删字典,if/elif/else分支结构for/while循环
try/finally/except捕获开始/是否异常都在离开try结构时执行/捕获到异常后执行–可以加else设置如果没有异常,我再进行下一步操作,raise引发异常
global声明全局变量,nonlocal如果函数里嵌套了函数,里面的函数要使用外面函数的变量,则要它声明为非本地
in/not in 成员运算存在性判断,is身份运算,lambda定义lambda函数关键字,pass 占位空语句
return返回关键字,yield生成器函数
取生成器的内容:1.next(这个生成器)执行一次拿一个,拿不到了报异常,2.for value in 生成器:拿完为止
正则命名捕获组:名字=re.complie(r’正则(?P<名字>捕获组)’) 我们在用这个正则.search(内容)时拿到的正则内容就是有名字的
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/290412.html