系列文章目录
python基础①-基础环境搭建和工具使用
python基础②-常用的各种数据类型初认知
python基础③-数据类型常用的操作和方法字符串、数值、bool
python基础④-数据类型常用的操作和方法列表、元组、字典、集合
python基础⑤-控制流程
python基础⑥-函数
python基础⑦-字符编码与文件操作
python基础⑧-异常
python基础⑨-迭代器和生成器
python基础⑩-面向对象
python基础⑪-继承与派生
python基础⑫-多进程
python基础⑬-多线程
python基础⑭-进程池、线程池、协程
python基础⑮-网络编程socket
python基础⑯-网络编程socket进阶
文章目录
为什么要有进程池和线程池?
开辟进程线程比较耗费资源。那些已经执行完任务的进程和线程不应该被关闭。而是应该利用起来给别的任务执行使用
进程池
计算机开进程或者线程受限于计算机本身的硬件,所以就有了进程池和线程池限制最大进程或者线程数
不会造新的进程或者线程,不会浪费内存空间
提交任务的两种方式:
同步调用:提交完一个任务之后,就在原地等待,等待任务完完整整地运行完毕拿到结果后,再执行下一行代码,会导致任务是串行执行的
提交任务的方法,串行是任务的运行状态
异步调用:提交完一个任务之后,不在原地等待,结果???,而是直接执行下一行代码,会导致任务是并发执行的
future.result() 会阻塞当前线程。当提交的任务执行完了才会解除阻塞并获取结果。异步提交其实就是一股脑先提交。最后一把获取结果
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time, os, random
def task(name):
print('%s%s is running' % (name, os.getpid()))
time.sleep(random.randint(1, 3))
return 123
if __name__ == '__main__':
print(os.cpu_count())
# 不写就是自己cpu的核数
# 不写就是自己cpu的核数
p = ProcessPoolExecutor(4)
# 只会开4个进程的id
for i in range(20):
# p.submit(task,'进程pid')
# 返回值
future = p.submit(task, '进程pid')
# print(future)
# 同步调用
print(future.result())
print('主')
# 异步提交
l = []
for i in range(10):
# p.submit(task,'进程pid')
# 返回值
future = p.submit(task, '进程pid')
# print(future)
# 同步调用
l.append(future)
# print(future.result())
# #关闭进程池的入口,并且在原地等待进程池内所有任务运行完毕
p.shutdown(wait=True)
for future in l:
# 一次性全部拿到结果
print(future.result())
print('主')
线程池
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
from threading import Thread, Lock, currentThread
import time, os, random
def task(name):
thread = currentThread()
print('%s%s is running' % (name, thread.ident))
time.sleep(random.randint(1, 3))
return 123
if __name__ == '__main__':
print(os.cpu_count())
p = ThreadPoolExecutor()
for i in range(20):
# p.submit(task,'线程标识')
# 返回值
future = p.submit(task, '线程标识')
print(future)
# 同步调用
print(future.result())
print('主')
# 异步提交
l = []
for i in range(10):
# p.submit(task,'线程标识')
# 返回值
future = p.submit(task, '线程标识')
# print(future)
# 同步调用
l.append(future)
# print(future.result())
# #关闭进程池的入口,并且在原地等待进程池内所有任务运行完毕
p.shutdown(wait=True)
for future in l:
# 一次性全部拿到结果
print(future.result())
print('主')
协程
在线程下实现并发
操作系统认为最小单位是线程
并发(多个任务看起来是同时执行就是并发):切换+保存状态(操作系统)
多线程是多个线程,线程在一个进程里面,线程之间切换,整个程序
多进程其实也是多个线程,线程分散到不同进程里面了,进程之间切换,整个程序
线程遇到io阻塞
应用程序级别来控制切换多个任务
遇到io操作切换才有意义
协程
协程是单线程实现并发,又称微线程
注意:协程是程序员想象出来的东西,操作系统里只有进程和线程的概念(操作系统调度的是线程)
在单线程下实现多个任务间遇到IO就切换就可以降低单线程的IO时间,从而最大限度地提升单线程的效率
没有遇到io切换会降低效率
遇到io切换会增加效率
链接循环和通信循环,并没有解决单线程下的io问题
协程可以把单个线程的效率最高
简单来说就是协程就是为了进一步避免遇到io操作时,多线程切换导致的资源损耗。遇到io操作时。在同一个线程里面的协程来切换。这是代码逻辑上的切换。不涉及操作系统。所以性能很高
# 安装模块
# pip install gevent
# 1.必须要放到文件的开头
# 打标记
from gevent import monkey
# 所有的io行为进行打包
monkey.patch_all()
# 导入gevent管理的任务
from gevent import spawn, joinall
import time
def play(name):
print('%s play 1' % name)
time.sleep(5)
print('%s play 2' % name)
def eat(name):
print('%s eat 1' % name)
time.sleep(3)
print('%s eat 2' % name)
start = time.time()
# 异步提交任务,不管结果,直接运行下行代码
g1 = spawn(play, '小王')
g2 = spawn(eat, '小戴')
# g1.join()
# g2.join()
# 一行代码搞定
joinall([g1, g2])
# 不同的python版本可能不一样。我用的 3.9版本主线程会等待所有协程执行完才会关闭
# time.sleep(4)
# 线程死了没了
print('主', time.time() - start)