python Event事件、进程池与线程池、协程解析
Python  /  管理员 发布于 7年前   189
Event事件
用来控制线程的执行
出现e.wait(),就会把这个线程设置为False,就不能执行这个任务;
只要有一个线程出现e.set(),就会告诉Event对象,把有e.wait的用户全部改为True,剩余的任务就会立马去执行。由一些线程去控制另一些线程,中间通过Event。
from threading import Eventfrom threading import Threadimport time# 调用Event实例化出对象e = Event()## # 若该方法出现在任务中,则为False,阻塞# e.wait() # False# # 若该方法出现在任务中,则将其他线程的False改为True,进入就绪态和运行态# e.set() # Truedef 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 ThreadPoolExecutorimport timepool = 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 ThreadPoolExecutorimport timepool = 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套接字
协程
注意: 协程不是操作系统资源,目的是让单线程实现并发
协程目的
优点:在IO密集型的情况下,会提高效率
缺点:若在计算密集型的情况下,来回切换,反而效率更低
import timedef func1(): for i in range(10000000): i+1def func2(): for i in range(10000000): i+1start = time.time()func1()func2()stop = time.time()print(stop - start) # 1.0312113761901855# 基于yield实现并发 在计算密集型的情况下效率更低def func1(): while True: 10000000+1 yielddef 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 timefrom gevent import monkeymonkey.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 monkeyfrom gevent import spawnimport socketmonkey.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 socketfrom threading import Thread, current_threaddef 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 += 1for i in range(400): t = Thread(target=client) t.start()
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
122 在
学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..123 在
Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..原梓番博客 在
在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..博主 在
佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..1111 在
佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
Copyright·© 2019 侯体宗版权所有·
粤ICP备20027696号