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()

进程池与线程池

  1. 进程池与线程池是用来控制当前程序允许创建(进程/线程)的数量

  2. 作用:保证在硬件允许的范围内创建(进程/线程)的数量

线程池使用一:

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套接字

  1. 主页中获取所有视频id号,拼接视频详情页url
  2. 在视频详情页中获取真实视频url srcUrl=
  3. 往真实视频url地址发送请求获取 视频 二进制数据
  4. 最后把视频二进制数据保存到本地

协程

  • 进程: 资源单位
  • 线程: 执行单位
  • 协程: 在单线程下实现并发

注意: 协程不是操作系统资源,目的是让单线程实现并发

协程目的

  • 操作系统:使用多道技术,切换 + 保存状态,一个是遇到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()

Event事件、进程池与线程池、协程的更多相关文章

  1. GIL与普通互斥锁区别,死锁现象,信号量,event事件,进程池与线程池,协程

    GIL与普通互斥锁区别 GIL锁和互斥锁的异同点 相同: 都是为了解决解释器中多个线程资源竞争的问题 异: 1.互斥锁是Python代码层面的锁,解决Python程序中多线程共享资源的问题(线程数据共 ...

  2. 进程池与线程池基本使用、协程理论与实操、IO模型、前端、BS架构、HTTP协议与HTML前戏

    昨日内容回顾 GIL全局解释器锁 1.在python解释器中 才有GIL的存在(只与解释器有关) 2.GIL本质上其实也是一把互斥锁(并发变串行 牺牲效率保证安全) 3.GIL的存在 是由于Cpyth ...

  3. python系列之 - 并发编程(进程池,线程池,协程)

    需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...

  4. python并发编程之进程池,线程池,协程

    需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...

  5. Python 37 进程池与线程池 、 协程

    一:进程池与线程池 提交任务的两种方式: 1.同步调用:提交完一个任务之后,就在原地等待,等任务完完整整地运行完毕拿到结果后,再执行下一行代码,会导致任务是串行执行 2.异步调用:提交完一个任务之后, ...

  6. 8.15 day33 进程池与线程池_协程_IO模型(了解)

    进程池和线程池 开进程开线程都需要消耗资源,只不过两者比较的情况线程消耗的资源比较少 在计算机能够承受范围之内最大限度的利用计算机 什么是池? ​ 在保证计算机硬件安全的情况下最大限度地利用计算机 ​ ...

  7. 进程池和线程池、协程、TCP单线程实现并发

    一.进程池和线程池 当被操作对象数目不大时,我们可以手动创建几个进程和线程,十几个几十个还好,但是如果有上百个上千个.手动操作麻烦而且电脑硬件跟不上,可以会崩溃,此时进程池.线程池的功效就能发挥了.我 ...

  8. Python Django 协程报错,进程池、线程池与异步调用、回调机制

    一.问题描述 在Django视图函数中,导入 gevent 模块 import gevent from gevent import monkey; monkey.patch_all() from ge ...

  9. python并发编程之进程池、线程池、协程

    需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...

随机推荐

  1. BurpSuite的基础使用,这个教程有“坑”?

    BurpSuite简介 BurpSuite是一款辅助渗透的工具,可以给我们带来许多便利.Burp给我们提供了简单的HTTP抓包改包,数据枚举模块,以及各种安全漏洞的手动式扫描与爬虫式扫描,还有很多经常 ...

  2. iOS多线程定时器

    在使用定时器时,我们经常使用NSTimer,但是由于NSTimer会受RunLoop影响,当RunLoop处理的任务很多时,就会导致NSTimer的精度降低,所以在一些对定时器精度要求很高的情况下,应 ...

  3. 通过Android反编译技术研究国内陌生人社交即时通讯的技术方案

    版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/100 即时通讯IM类App分析 这两周对国内陌生人社交领域 ...

  4. Python完全平方数

    python解题源代码如下: import math """ 简述:一个整数,它加上100和加上268后都是一个完全平方数 提问:请问该数是多少? Python解题思路分 ...

  5. s3c2440裸机-内存控制器(一、内存控制器的原理)

    1.内存接口概念 S3C2440是个片上系统,有GPIO控制器(接有GPIO管脚(GPA-GPH)),有串口控制器 (接有TXD RXD引脚),有memory controller内存控制器,有Nan ...

  6. RabbitMQ学习笔记(七、RabbitMQ实战)

    目录: 削峰 分布式事务 削峰: 利用RabbitMQ队列消费特性避免峰值下的DB访问,缓解连接压力,在DB释放连接后再去消息数据. 分布式事务: )XA协议:它是一个分布式事务协议,由事务管理器和资 ...

  7. 开发工具IntelliJ IDEA

    开发工具概述 IDEA是一个专门针对Java的集成开发工具(IDE),由Java语言编写.所以,需要有JRE运行环境并配置好环境变量.它可以极大地提升我们的开发效率.可以自动编译,检查错误.在公司中, ...

  8. LG5202 「USACO2019JAN」Redistricting 动态规划+堆/单调队列优化

    问题描述 LG5202 题解 \[opt[i]=xx+(cnt[i]-cnt[yy]<=0)\] 发现\(cnt[i]-cnt[yy] <= 0\)只能有两种取值 于是直接堆优化即可 \( ...

  9. Codeforces Round #597 (Div. 2) F. Daniel and Spring Cleaning 数位dp

    F. Daniel and Spring Cleaning While doing some spring cleaning, Daniel found an old calculator that ...

  10. HTML连载41-水平居中的注意点、盒子居中和内容居中

    一.盒子模型练习 我们有个需求: 创建两个盒子,大盒子嵌套一个小盒子,大盒子是红色的,小盒子是蓝色的,并且小盒子在大盒子中是居中的. <!DOCTYPE html> <html la ...