python Event事件、进程池与线程池、协程解析
作者:SetCreed 发布时间:2023-09-06 00:39:19
Event事件
用来控制线程的执行
出现e.wait(),就会把这个线程设置为False,就不能执行这个任务;
只要有一个线程出现e.set(),就会告诉Event对象,把有e.wait的用户全部改为True,剩余的任务就会立马去执行。由一些线程去控制另一些线程,中间通过Event。
from threading import Event
from threading import Thread
import time
# 调用Event实例化出对象
e = Event()
#
# # 若该方法出现在任务中,则为False,阻塞
# e.wait() # False
# # 若该方法出现在任务中,则将其他线程的False改为True,进入就绪态和运行态
# e.set() # True
def light():
print('红灯亮...')
time.sleep(5)
# 应该发出信号,告诉其他线程准备执行
e.set() # 将car中的False变为True
print('绿灯亮...')
def car(name):
print('正在等红灯...')
# 让所有汽车任务进入阻塞态
e.wait() # False
print(f'{name}正在加速飘逸...')
# 让一个light线程控制多个car线程
t = Thread(target=light)
t.start()
for i in range(10):
t = Thread(target=car, args=(f'汽车{i}号', ))
t.start()
进程池与线程池
进程池与线程池是用来控制当前程序允许创建(进程/线程)的数量
作用:保证在硬件允许的范围内创建(进程/线程)的数量
线程池使用一:
from concurrent.futures import ThreadPoolExecutor
import time
pool = ThreadPoolExecutor(5) # 5代表只能开启5个进程, 不加默认使用cpu的进程数
# ThreadPoolExecutor(5) # 5代表只能开启5个线程
# pool.submit() #异步提交任务, 括号里传函数地址
def task():
print('线程任务开始了...')
time.sleep(1)
print('线程任务结束了...')
for line in range(5):
pool.submit(task)
使用二:
from concurrent.futures import ThreadPoolExecutor
import time
pool = ThreadPoolExecutor(5) # 5代表只能开启5个进程, 不加默认使用cpu的进程数
# ThreadPoolExecutor(5) # 5代表只能开启5个线程
# pool.submit() #异步提交任务, 括号里传函数地址
def task():
print('线程任务开始了...')
time.sleep(1)
print('线程任务结束了...')
return 123
# 回调函数
def call_back(res):
print(type(res))
res2 = res.result() # 注意:赋值操作不要与接收的res同名
print(res2)
for line in range(5):
pool.submit(task).add_done_callback(call_back)
pool.shutdown() 会让所有线程池的任务结束后,才往下执行代码
多线程爬取梨视频
利用requests模块,封装底层socket套接字
主页中获取所有视频id号,拼接视频详情页url
在视频详情页中获取真实视频url srcUrl=
往真实视频url地址发送请求获取 视频 二进制数据
最后把视频二进制数据保存到本地
协程
进程: 资源单位
线程: 执行单位
协程: 在单线程下实现并发
注意: 协程不是操作系统资源,目的是让单线程实现并发
协程目的
操作系统:使用多道技术,切换 + 保存状态,一个是遇到IO, 另一个是CPU执行时间过长
协程:通过手动模拟操作系统 “多道计数”, 实现 切换 + 保存状态
手动实现,遇到IO切换,欺骗操作系统误以为没有IO操作
单线程时,遇到IO,就切换 + 保存状态
单线程时,对于计算密集型,来回切换 + 保存状态反而效率更低
优点:在IO密集型的情况下,会提高效率
缺点:若在计算密集型的情况下,来回切换,反而效率更低
import time
def func1():
for i in range(10000000):
i+1
def func2():
for i in range(10000000):
i+1
start = time.time()
func1()
func2()
stop = time.time()
print(stop - start) # 1.0312113761901855
# 基于yield实现并发 在计算密集型的情况下效率更低
def func1():
while True:
10000000+1
yield
def func2():
g = func1()
for i in range(10000000):
i+1
next(g) # 每次执行next相当于切换到func1下面
start = time.time()
func2()
stop = time.time()
print(stop - start) # 1.3294126987457275
gevent
gevent是一个第三方模块,可以帮你监听IO操作,并切换
使用gevent的目的:在单线程下实现,遇到IO就会 保存状态 + 切换
import time
from gevent import monkey
monkey.patch_all() # 可以监听该程序下所有的IO操作
from gevent import spawn, joinall # 用于做切换 + 保存状态
def func1():
print('1')
time.sleep(1) # IO操作
def func2():
print('2')
time.sleep(3)
def func3():
print('3')
time.sleep(5)
start = time.time()
s1 = spawn(func1)
s2 = spawn(func2)
s3 = spawn(func3)
s1.join() # 发送信号,相当于等待自己(在单线程的情况下)
s2.join()
s3.join()
# joinall((s1, s2, s3)) # 一个个执行很麻烦,可以用joinall把这些全部装进去
end = time.time()
print(end - start) # 5.006161451339722
TCP服务端socket套接字实现协程
服务端:
from gevent import monkey
from gevent import spawn
import socket
monkey.patch_all()
server = socket.socket()
server.bind(('127.0.0.1', 9999))
server.listen(5)
def task(conn):
while True:
try:
data = conn.recv(1024)
if len(data) == 0:
break
print(data.decode('utf-8'))
send_data = data.upper()
conn.send(send_data)
except Exception:
break
conn.close()
def server2():
while True:
conn, addr = server.accept()
print(addr)
spawn(task, conn)
if __name__ == '__main__':
s = spawn(server2)
s.join()
客户端:
import socket
from threading import Thread, current_thread
def client():
client = socket.socket()
client.connect(('127.0.0.1', 9999))
number = 0
while True:
send_data = f'{current_thread().name} {number}'
client.send(send_data.encode('utf-8'))
data = client.recv(1024)
print(data.decode('utf-8'))
number += 1
for i in range(400):
t = Thread(target=client)
t.start()
来源:https://www.cnblogs.com/setcreed/p/11735441.html


猜你喜欢
- 目录简介快速使用格式时区cli总结参考简介不管什么时候,处理时间总是让人头疼的一件事情。因为时间格式太多样化了,再加上时区,夏令时,闰秒这些
- 常用的重定向方式有: 301 redirect, 302 redirect 与 meta fresh:301 redirect: 301代表
- 上一章节我们学习了如何生成 word 文档以及在文档行中添加各种内容,今天我们基于上一章节的内容进行添砖加瓦 —>
- 引言上次给大家分享了:《1行Python代码,实现增值税发票识别》。在那个视频的开始,也预告了本篇的内容:把识别的发票内容,分门别类的写进E
- 其主要的优点便是无需再手工添加大量的信息了,可以指定对某一个站信息的截取进行批量录入,达到省时省力的目的。与其单纯的ASP小偷程序不同的是:
- 本文实例讲述了php+mysqli使用面向对象方式更新数据库的方法,分享给大家供大家参考。具体实现方法如下:<?php//第一步:创建
- 在画一些曲线图(linecharts)时,常常会出现多条曲线同时画在一张图上面,这时候就需要对不同的曲线进行不同的标注,以使读者能够清晰地知
- 交互式命令行是一种方便用户进行交互的工具,能够使用户与计算机进行快速的交互操作,提高工作效率。Python pyreadline模块可以帮助
- 一、总结apply —— 应用在 dataFrame 上,用于对 row 或者 column 进行计算applymap —— 应用在 dat
- enumerate函数用于遍历序列中的元素以及它们的下标。enumerate函数说明:函数原型:enumerate(sequence, [s
- 安装paramiko后,看下面例子:import paramiko#设置ssh连接的远程主机地址和端口t=paramiko.Transpor
- 本文为大家分享了python实现学生管理系统的具体代码,供大家参考,具体内容如下1.0版本学生管理系统''' 1.添
- 在前面实现了平移和缩放,还有一种常用的坐标变换,那就是旋转。比如拍摄的照片上传到电脑里,再打开时发现人的头在下面脚在上,这样肯定看不了,那么
- QQ影音至9月发布之后一直口碑很好,视觉界面和交互设计也颇受好评,这是设计师们努力的结果,也是众多用户反馈的功劳。我们希望可以提供更多价值回
- 操作所涉及的文件都在当前用户下面的隐藏文件:1. 打开Anaconda Prompt(如果之前生成过Config配置文件则不需要第一步)终端
- 问题setInterval 是间隔调用,与之类似的还有 setTimeout。这两个 API 通常用来做 ajax 短连接轮询数据。比如有一
- 一、前言近期在实际项目中使用到了PID控制算法,于是就该算法做一总结。二、PID控制算法详解2.1 比例控制算法例子: 假设一个水缸,需要最
- 最近在学习正则,一些比较有用的东西怕忘记,记下来,比较乱,想一条记录一条:正则表达式在线测试//匹配文本,这个偶尔比较好用,但是要小心字符中
- #!/usr/bin/python #-*- encoding: utf-8 -*- import types class NotInteg
- 网上一直说的是先安装SQL Server 2014,再安装VS2015,软件就不会出现问题。我这次在什么都没准备的情况下安装了VS2015,