iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Python全栈之协程详解
  • 257
分享到

Python全栈之协程详解

2024-04-02 19:04:59 257人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录1.线程队列2.进程池_线程池3.回调函数4.协程总结:1. 线程队列 # ### 线程队列 from queue import Queue """ put 存放 超出队列长

1. 线程队列


# ### 线程队列
from queue import Queue
"""
put 存放 超出队列长度阻塞
get 获取 超出队列长度阻塞
put_nowait 存放,超出队列长度报错
get_nowait 获取,超出队列长度报错
"""
# (1) Queue 
"""先进先出,后进先出"""
q = Queue()
q.put(100)
q.put(200)
print(q.get())
# print(q.get())
# print(q.get()) 阻塞
# print(q.get_nowait())
# print(q.get_nowait()) 报错
# Queue(3)  =>  指定队列长度, 元素个数只能是3个;
q2 = Queue(3)
q2.put(1000)
q2.put(2000)
# q2.put(3000)
# q2.put(4000) 阻塞
q2.put_nowait(6000)
# q2.put_nowait(4000) 报错
# (2) LifoQueue 
"""先进后出,后进先出(栈的特点)"""
from queue import LifoQueue
lq = LifoQueue()
lq.put(110)
lq.put(120)
lq.put(119)
print(lq.get())
print(lq.get())
print(lq.get())
# (3) PriorityQueue
"""按照优先级顺序进行排序存放(默认从小到大)"""
"""在一个优先级队列中,要放同一类型的数据,不能混合使用"""
from queue import PriorityQueue
pq = PriorityQueue()
# 1.对数字进行排序
pq.put(100)
pq.put(19)
pq.put(-90)
pq.put(88)
print(pq.get())
print(pq.get())
print(pq.get())
print(pq.get())
# 2.对字母进行排序 (按照ascii编码)
pq.put("wangwen")
pq.put("sunjian")
pq.put('wangwei')
pq.put("王文")
pq.put("孙坚")
pq.put('王维')
print( pq.get() )
print( pq.get() )
print( pq.get() )
print( pq.get() )
print( pq.get() )
print( pq.get() )
# 3.对容器进行排序
pq.put( (22,"wangwen") )
pq.put( (67,"wangyuhan") )
pq.put( (3,"anxiaodong") )
pq.put( (3,"liuyubo") )
print(pq.get())
print(pq.get())
print(pq.get())
print(pq.get())
# 4.注意点
pq.put(100)
pq.put("nihao")
pq.put( (1,2,3) )

2. 进程池_线程池

知识点:


# 线程池
    # 实例化线程池      ThreadPoolExcutor    (推荐5*cpu_count)
    # 异步提交任务      submit / map
    # 阻塞直到任务完成   shutdown
    # 获取子线程的返回值 result
    # 使用回调函数      add_done_callback
# 线程池 是由子线程实现的
# 进程池 是由主进程实现的  

程序实现:


# ### 进程池 和 线程池
from concurrent.futures import ProcessPoolExecutor , ThreadPoolExecutor
import os,time,random
# 获取的逻辑处理器
# print(os.cpu_count())
"""多条进程提前开辟,可触发多cpu的并行效果"""
'''
# (1) 进程池 ProcessPoolExecutor
def func(i):
	# print(i)
	time.sleep(random.unifORM(0.1,0.8))
	print(" 任务执行中 ...  start ... 进程号{}".format(os.getpid()) , i )
	print(" 任务执行中 ...  end ... 进程号{}".format(os.getpid()))
	return i
if __name__ == "__main__":
	lst = []
	# (1) 创建进程池对象
	"""默认参数是 系统最大的逻辑核心数 4"""
	p = ProcessPoolExecutor()
	# (2) 异步提交任务
	"""submit(任务,参数1,参数2 ... )"""
	"""默认如果一个进程短时间内可以完成更多的任务,进程池就不会使用更多的进程来辅助完成 , 可以节省系统资源的损耗;"""
	for i in range(10):
		obj = p.submit( func , i )
		# print(obj)
		# print(obj.result()) 不要写在这,导致程序同步,内部有阻塞
		lst.append(obj)
	# (3) 获取当前任务的返回值
	for i in lst:
		print(i.result(),">===获取返回值===?")
	# (4) shutdown 等待所有进程池里的进程执行完毕之后,在放行
	p.shutdown()
	print("进程池结束 ... ")
'''
# (2) ThreadPoolExecutor
'''
# from threading import currentThread as ct
from threading import current_thread as ct
def func(i):
	print(" 任务执行中 ...  start ... 线程号{}".format( ct().ident ) , i )
	time.sleep(1)
	print(" 任务执行中 ...  end ... 线程号{}".format(os.getpid()))
	return ct().ident  # 线程号
if __name__ == "__main__":
	lst = []
	setvar = set()
	"""默认参数是 系统最大的逻辑核心数 4 * 5 = 20"""
	# (1) 创建线程池对象
	t = ThreadPoolExecutor() # 20
	# print(t)
	# (2) 异步提交任务
	"""默认如果一个线程短时间内可以完成更多的任务,线程池就不会使用更多的线程来辅助完成 , 可以节省系统资源的损耗;"""
	for i in range(100):
		obj = t.submit(func,i)
		lst.append(obj)
	# (3) 获取当前任务的返回值
	for i in lst:
		setvar.add(i.result())		
	# (4) shutdown 等待所有线程池里的线程执行完毕之后,在放行
	t.shutdown()
	print("主线程执行结束 ... ")	
	print(setvar , len(setvar))
'''
# (3) 线程池 map
from threading import currentThread as ct
from collections import Iterator,Iterable
def func(i):
	time.sleep(random.uniform(0.1,0.7))
	print("thread ... 线程号{}".format(ct().ident),i)
	return "*" * i
if __name__ == "__main__":
	t = ThreadPoolExecutor()
	it = t.map(func,range(100))
	# 返回的数据是迭代器
	print(isinstance(it,Iterator))
	# 协调子父线程,等待线程池中所有线程执行完毕之后,在放行;
	t.shutdown()
	# 获取迭代器里面的返回值
	for i in it:
		print(i)
"""
# 总结: 无论是进程池还是线程池,都是由固定的进程数或者线程数来执行所有任务
系统不会额外创建多余的进程或者线程来执行任务;
"""

3. 回调函数

知识点:


# 回调函数
    就是一个参数,将这个函数作为参数传到另一个函数里面.
    函数先执行,再执行当参数传递的这个函数,这个参数函数是回调函数

程序实现:


# ### 回调函数
"""
回调函数: 回头调用一下函数获取最后结果
微信支付宝付款成功后, 获取付款金额
微信支付宝退款成功后, 获取退款金额
一般用在获取最后的状态值时,使用回调
通过add_done_callback最后调用一下自定义的回调函数;
"""
from concurrent.futures import ProcessPoolExecutor , ThreadPoolExecutor
from threading import currentThread as ct
import os,time,random
"""进程任务"""
def func1(i):
	time.sleep(random.uniform(0.1,0.9))
	print(" 进程任务执行中 ...  start ... 进程号{}".format(os.getpid()) , i )
	print(" 进程任务执行中 ...  end ... 进程号{}".format(os.getpid()) )
	return i
def call_back1(obj):
	print(   "<==回调函数的进程号{}==>".format(os.getpid())   )
	print(obj.result())
"""线程任务"""	
def func2(i):
	time.sleep(random.uniform(0.1,0.9))
	print(" 线程任务执行中 ...  start ... 线程号{}".format(ct().ident) , i )
	print(" 线程任务执行中 ...  end ... 线程号{}".format( ct().ident) )
	return i
def call_back2(obj):
	print(   "<==回调函数的线程号{}==>".format(  ct().ident) )
	print(obj.result())
if __name__ == "__main__":
	"""		
	# (1)进程池  结果:(进程池的回调函数由主进程执行)
	p = ProcessPoolExecutor() # os.cpu_count()  => 4
	for i in range(1,11):
		obj = p.submit(func1 , i )
		# 使用add_done_callback在获取最后返回值的时候,可以异步并行
		obj.add_done_callback(call_back1)
		# 直接使用result获取返回值的时候,会变成同步程序,速度慢;
		# obj.result()
	p.shutdown()		
	print(   "主进程执行结束...进程号:"    ,    os.getpid()  )
	"""
	print("<==============================================>")
	# (2)线程池  结果:(线程池的回调函数由子线程执行)
	t = ThreadPoolExecutor()
	for i in range(1,11):
		obj = t.submit(func2 , i )
		# 使用add_done_callback在获取最后返回值的时候,可以异步并发
		obj.add_done_callback(call_back2)
		# 直接使用result获取返回值的时候,会变成同步程序,速度慢;
		# obj.result()
	t.shutdown()
	print("主线程执行结束 .... 线程号{}".format(ct().ident))
"""
# 原型:
class Ceshi():
	def add_done_callback(self,func):
		print("系统执行操作1 ... ")
		print("系统执行操作2 ... ")
		# 回头调用一下
		func(self)
	def result(self):
		return 112233
def call_back(obj):
	print(obj.result())
obj = Ceshi()
obj.add_done_callback(call_back)
"""

4. 协程

知识点:


#协程也叫纤程: 协程是线程的一种实现方式.
    指的是一条线程能够在多任务之间来回切换的一种实现.
    对于CPU、操作系统来说,协程并不存在.
    任务之间的切换会花费时间.
    目前电脑配置一般线程开到200会阻塞卡顿.
#协程的实现
协程帮助你记住哪个任务执行到哪个位置上了,并且实现安全的切换
一个任务一旦阻塞卡顿,立刻切换到另一个任务继续执行,保证线程总是忙碌的,更加充分的利用CPU,抢占更多的时间片
# 一个线程可以由多个协程来实现,协程之间不会产生数据安全问题
#协程模块
    # greenlet  gevent的底层,协程,切换的模块
    # gevent    直接用的,gevent能提供更全面的功能

程序实现:


# ### 协程 
"""
进程是资源分配的最小单位
线程是程序调度的最下单位
协程是线程实现的具体方式
总结:
在进程一定的情况下,开辟多个线程,
在线程一定的情况下,创建多个协程,
以便提高更大的并行并发
"""
# (1) 用协程改写生产者消费者模型
"""
def producer():
	for i in range(1000):
		yield i
def consumer(gen):
	for i in range(10):
		print(  next(gen)  )
gen = producer()
consumer(gen)
print("<==========>")
consumer(gen)
print("<==========>")
consumer(gen)
"""
# (2) greenlet 协程的早期版本
from greenlet import greenlet
import time
""" switch 可以切换任务,但是需要手动切换"""
"""
def eat():
	print("eat1")
	g2.switch()
	time.sleep(3)
	print("eat2")
def play():
	print("play1")	
	time.sleep(3)
	print("play2")
	g1.switch()
g1 = greenlet(eat)
g2 = greenlet(play)
g1.switch()
"""
# (3) 升级到gevent版本
"""自动进行任务上的切换,但是不能识别阻塞"""
"""
import gevent
def eat():
	print("eat1")
	gevent.sleep(3)
	# time.sleep(3)
	print("eat2")
def play():
	print("play1")
	gevent.sleep(3)	
	# time.sleep(3)
	print("play2")
# 利用gevent.spawn创建协程对象g1
g1 = gevent.spawn(eat)
# 利用gevent.spawn创建协程对象g2
g2 = gevent.spawn(play)
# 如果不加join, 主线程直接结束任务,不会默认等待协程任务.
# 阻塞,必须等待g1任务完成之后在放行
g1.join()
# 阻塞,必须等待g2任务完成之后在放行
g2.join()
print("主线程执行结束 ....  ")
"""
# (4) 协程的终极版本;
from gevent import monkey;monkey.patch_all()
"""引入猴子补丁,可以实现所有的阻塞全部识别"""
import time
import gevent
def eat():
	print("eat1")
	time.sleep(3)
	print("eat2")
def play():
	print("play1")
	time.sleep(3)
	print("play2")
# 利用gevent.spawn创建协程对象g1
g1 = gevent.spawn(eat)
# 利用gevent.spawn创建协程对象g2
g2 = gevent.spawn(play)
# 如果不加join, 主线程直接结束任务,不会默认等待协程任务.
# 阻塞,必须等待g1任务完成之后在放行
g1.join()
# 阻塞,必须等待g2任务完成之后在放行
g2.join()
print(" 主线程执行结束 ... ")
"""
# 分号,利用分号可以把多行代码放在一行进行编写;
a = 1
b = 2
a = 1;b = 2
"""

==理解:==一个线程上有好多任务,协程可以记住每个任务完成的状态,比如做饭的时候做到一半的时候停下来,去扫地,扫完地之后拐回来做饭,从做到一半的时候开始做。

在这里插入图片描述

小提示: 下载gevent包,会自带greenlet

在这里插入图片描述

早期版本的想到在time.sleep执行了两次,每次执行了一秒钟,切换回来有执行了一秒,这是模拟早期版本,模拟堵塞

在这里插入图片描述

总结:


p.shutdown() 这里的shutdown类似于join
生成器在实例化对象的时候,里面的代码是不走的,调用的时候才有,next
调用等
单线程实现的一种异步并发的一种结构
协程能记住任务的状态

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: Python全栈之协程详解

本文链接: https://www.lsjlt.com/news/160820.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Python全栈之协程详解
    目录1.线程队列2.进程池_线程池3.回调函数4.协程总结:1. 线程队列 # ### 线程队列 from queue import Queue """ put 存放 超出队列长...
    99+
    2024-04-02
  • Python全栈之线程详解
    目录1. 线程的概念1.1 Manager_进程通信1.2 线程的概念2. 线程的基本使用3. 自定义线程_守护线程3.1 自定义线程3.2 守护线程4. 线程安全问题4.1 线程安...
    99+
    2024-04-02
  • Python全栈之队列详解
    目录1.lock互斥锁2.事件_红绿灯效果2.1信号量_semaphore2.2事件_红绿灯效果3.queue进程队列4.生产者消费者模型5.joinablequeue队列使用6.总...
    99+
    2024-04-02
  • Python全栈之运算符详解
    目录1. 算数_比较_赋值_成员1.1 算数运算符1.2 比较运算符1.3 赋值运算符1.4 成员运算符2. 身份运算符小提示:3. 逻辑运算符3.1 位运算符3.2 小总结4. 代...
    99+
    2024-04-02
  • Python全栈之模板渲染详解
    目录1. 标签1.1 for循环标签1.2 if标签1.3 with标签1.4 csrf token标签2. 模板继承3. 组件4. 自定义过滤器5. 自定义标签6. inclusi...
    99+
    2024-04-02
  • Python进阶之协程详解
    目录协程协程的应用场景抢占式调度的缺点用户态协同调度的优势协程的运行原理Python 中的协程总结协程 协程(co-routine,又称微线程)是一种多方协同的工作方式。当前执行者在...
    99+
    2024-04-02
  • python 全栈之路
    目录 Python 全栈之路 一. Python 1. Python基础知识部分 2. Python -函数 3. ...
    99+
    2023-01-30
    之路 python
  • Python全栈之路系列之Python
    The Python interpreter has a number of functions and types built into it that are always available. They are listed her...
    99+
    2023-01-31
    之路 系列之 Python
  • Python全栈之进程和守护进程
    目录1. 理解进程2. 进程的语法3. join自定义进程类4. 守护进程总结 1. 理解进程 进程的概念:(process) 进程就是正在运行的程序,它是操作系统中,资源分配的...
    99+
    2024-04-02
  • Python全栈开发之网络编程
    No.1 TCP/IP 早期的计算机网络,都是由厂商规定自己的通信协议,互不兼容,为了把全世界不同类型的计算机连接起来,就必须规定一套全球通用的协议,所以就出现了TCP/IP No.2 Socket简介 要解决怎么标识一个进制,在一台电...
    99+
    2023-01-31
    网络编程 Python
  • Python全栈开发之并发编程
    No.1 线程 什么是多任务 就是操作系统可以同时运行多个任务,就是可以一边用浏览器上网,同时又可以听歌,还能再撩个×××姐,这就是多任务,操作系统会轮流把系统调度到每个核心上去执行 并发和并行 并发是指任务数多余cpu核数,通过操作系统的...
    99+
    2023-01-31
    Python
  • Python数据结构之栈详解
    目录0. 学习目标1. 栈的基本概念1.1 栈的基本概念1.2 栈抽象数据类型1.3 栈的应用场景2. 栈的实现2.1 顺序栈的实现2.1.1 栈的初始化2.2 链栈的实现2.3 栈...
    99+
    2024-04-02
  • Python全栈之学习HTML
    目录1. vscode相关配置2. html认识2.1 html认识2.2 html结构2.3 html语法特征3. 标签种类_列表3.1 常见标签3.2 标签种类3.3 列表3.4...
    99+
    2024-04-02
  • Python全栈开发之Git
    No.1 Git 特点 版本控制:可以解决多人同时开发的代码问题,也可以找回历史代码 分布式:Git是一个分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上,首先会有一台计算机充当服务器,这台计算机7*24小时服务,其他计算机都...
    99+
    2023-01-31
    Python Git
  • Python全栈之jQuery笔记
    jQuery runnoob网址: http://www.runoob.com/jquery/jquery-tutorial.html jQuery API手册: http://www.runoob.com/manual/jquery/...
    99+
    2023-01-30
    笔记 Python jQuery
  • Python全栈开发之---assert
    一、python assert的作用: 根据Python 官方文档解释(https://docs.python.org/3/reference/simple_stmts.html#assert), "Assert statements a...
    99+
    2023-01-30
    Python assert
  • Python全栈之for循环
    目录1. 双向循环的练习2. break_pass_continue的使用3. for循环小提示:4. 小练习问题:答案:总结1. 双向循环的练习 # 1.用两个循环完成十行十列...
    99+
    2024-04-02
  • Python全栈之学习JQuery
    目录1. lable标签补充2. jquery引入和简单使用3. 选择器3.1 基础选择器3.2 组合选择3.3 层级选择器3.4 属性选择器3.5 表单对象属性选择器3.6 表单选...
    99+
    2024-04-02
  • Android Kotlin之Coroutine(协程)详解
    协程是一种并发设计模式,您可以在 Android 平台上使用它来简化异步执行的代码。 在 Android 上,协程有助于管理长时间运行的任务,如果管理不当,这些任务可能会阻塞主线程并导致应用无响应。 协程的优点: 轻量 您可以在单个线程上运...
    99+
    2023-08-16
    android kotlin 协程 Coroutine 异步
  • python全栈开发之Python基础(
    一、 基础知识 python的运行方式有两种: 第一种通过交互式的运行方式,通过 "开始"—>"所有程序" —> "python3.x" —>"IDLE" 运行。 第二种是我们写好的Python文件双击运行。 ...
    99+
    2023-01-31
    基础 python Python
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作