Event事件

  • 用来控制线程的执行
  • e.isSet()查看对象e当前的信号状态, 默认为False
  • e.wait() 信号状态为False, 则当前线程阻塞
  • e.set() 将e的信号状态设置为True, 被阻塞的线程进入非阻塞状态
from threading import Thread
from threading import Event
import time e = Event() def light():
print('*********红灯!**********')
print(f'对象当前的信号状态为{e.isSet()}')
time.sleep(5)
print('*********绿灯!**********')
e.set() # 将e的信号标准设为True
print(f'对象当前的信号状态为{e.isSet()}') def driver(name):
print(f'{name}正在等红灯!')
e.wait() # 如果e信号标志为False, 则当前线程阻塞
print(f'{name}弹射起步!') if __name__ == '__main__': t1 = Thread(target=light)
t1.start() for i in range(10):
t2 = Thread(target=driver, args=(f'老司机{i+1}号',))
t2.start() '''
**********红灯!**********
对象当前的信号状态为False
老司机1号正在等红灯!
老司机2号正在等红灯!
老司机3号正在等红灯!
老司机4号正在等红灯!
老司机5号正在等红灯!
老司机6号正在等红灯!
老司机7号正在等红灯!
老司机8号正在等红灯!
老司机9号正在等红灯!
老司机10号正在等红灯!
**********绿灯!**********
对象当前的信号状态为True
老司机1号弹射起步!
老司机5号弹射起步!
老司机7号弹射起步!
老司机8号弹射起步!
老司机9号弹射起步!
老司机6号弹射起步!
老司机4号弹射起步!
老司机2号弹射起步!
老司机10号弹射起步!
老司机3号弹射起步!
'''

线程池与进程池

基本概念

  • 用来控制当前程序允许创建进程/线程的数量
  • 防止程序创建的进程/线程过多, 超过硬件承受的范围

使用方法

  • pool = ProcessPoolExecutor(5) 当前任务最多只能同时开启5个进程, 默认线程个数是CPU个数
  • pool = ThreadPoolExecutor(5) 当前任务最多只能同时开启5个线程, 默认线程个数是CPU个数 * 5
  • pool.submit(函数地址, 参数) 提交任务
  • pool.submit(函数地址, 参数).add_done_callback(回调函数地址) 提交任务, 并把任务的返回值传给回调函数
  • pool.shutdown() 让线程池任务都执行完后再往下执行代码
from concurrent.futures import ThreadPoolExecutor
import time pool = ThreadPoolExecutor(5) # 送快递
def deliver(goods):
print(f'{goods}开始发货!')
time.sleep(1)
print(f'{goods}已经签收!')
return True # 拿快递(回调函数)
def get_goods(res):
get = res.result()
if get:
print('开始拆快递!')
else:
print('投诉!') for i in range(5):
pool.submit(deliver, f'格子衬衫牛仔裤{i+1}').add_done_callback(get_goods) # 让线程池中的线程运行完毕再执行下面的代码
pool.shutdown()
print('钱包空空!') '''
格子衬衫牛仔裤1开始发货!
格子衬衫牛仔裤2开始发货!
格子衬衫牛仔裤3开始发货!
格子衬衫牛仔裤4开始发货!
格子衬衫牛仔裤5开始发货!
格子衬衫牛仔裤1已经签收!
开始拆快递!
格子衬衫牛仔裤2已经签收!
开始拆快递!
格子衬衫牛仔裤5已经签收!
开始拆快递!
格子衬衫牛仔裤4已经签收!
开始拆快递!
格子衬衫牛仔裤3已经签收!
开始拆快递!
钱包空空!
'''

当我们想开启10个线程时, 既for i in range(10):, 结果如下

'''
格子衬衫牛仔裤1开始发货!
格子衬衫牛仔裤2开始发货!
格子衬衫牛仔裤3开始发货!
格子衬衫牛仔裤4开始发货!
格子衬衫牛仔裤5开始发货!
格子衬衫牛仔裤2已经签收!
开始拆快递!
格子衬衫牛仔裤6开始发货!
格子衬衫牛仔裤1已经签收!
开始拆快递!
格子衬衫牛仔裤7开始发货!
格子衬衫牛仔裤4已经签收!
格子衬衫牛仔裤3已经签收!
开始拆快递!
格子衬衫牛仔裤8开始发货!
格子衬衫牛仔裤5已经签收!
开始拆快递!
格子衬衫牛仔裤9开始发货!
开始拆快递!
格子衬衫牛仔裤10开始发货!
格子衬衫牛仔裤6已经签收!
开始拆快递!
格子衬衫牛仔裤10已经签收!
开始拆快递!
格子衬衫牛仔裤7已经签收!
开始拆快递!
格子衬衫牛仔裤8已经签收!
开始拆快递!
格子衬衫牛仔裤9已经签收!
开始拆快递!
钱包空空!
'''

和信号量的区别

  • 信号量: 工作线程是我们自己创建的, 需要我们手动进行限流
  • 线程池: 工作线程是线程池创建的, 线程池自动限流

协程(coroutine)

基本概念

  • 在单线程下实行并发(切换 + 保存)
  • 线程是系统级别的, 由操作系统调度. 协程是程序级别的, 需要程序员自己调度
  • 优点: 不需要上下文切换的开销, 节省空间和时间
  • 缺点: 无法利用多核优势, 进行阻塞操作会阻塞整个程序

实现方式

  • yield实现
import time

# 生成器
def consumer():
r = ''
while True:
n = yield r
if not n:
return
print(f'[CONSUMER] consuming {n}...')
time.sleep(1)
r = '200 OK' def producer(c):
c.__next__() # 初始化生成器
n = 0
while n < 5:
n = n + 1
print(f'[PRODUCER] producing {n}...')
r = c.send(n) # 切换到consumer执行
print(f'[PRODUCER] consumer return: {r}')
c.close() if __name__ == '__main__':
# c是生成器对象
c = consumer()
producer(c) '''
[PRODUCER] producing 1...
[CONSUMER] consuming 1...
[PRODUCER] consumer return: 200 OK
[PRODUCER] producing 2...
[CONSUMER] consuming 2...
[PRODUCER] consumer return: 200 OK
[PRODUCER] producing 3...
[CONSUMER] consuming 3...
[PRODUCER] consumer return: 200 OK
[PRODUCER] producing 4...
[CONSUMER] consuming 4...
[PRODUCER] consumer return: 200 OK
[PRODUCER] producing 5...
[CONSUMER] consuming 5...
[PRODUCER] consumer return: 200 OK
'''
  • gevent模块实现
from gevent import monkey;
monkey.patch_all() # 猴子补丁, 修改Python一些标准库
from gevent import spawn, joinall
import time def func1():
print('1')
time.sleep(1) def func2():
print('2')
time.sleep(2) def func3():
print('3')
time.sleep(3) start_time = time.time() s1 = spawn(func1)
s2 = spawn(func2)
s3 = spawn(func3) joinall([s1, s2, s3]) end_time = time.time() print(end_time - start_time) '''
1
2
3
3.007172107696533
'''

多线程爬取梨视频

from threading import Thread
import requests
import re # 访问链接
def access_page(url):
response = requests.get(url)
return response # 获取主页视频的id列表, 用来拼接视频详情页链接
def get_video_id(homepage_data):
id_list = re.findall('<a href="video_(.*?)" .*?>', homepage_data, re.S)
return id_list # 获取视频链接列表
def get_video_url(detail_page_data):
video_url = re.findall('srcUrl="(.*?)"', detail_page_data, re.S)[0]
return video_url # 获取视频名称
def get_video_name(detail_page_date):
video_name = re.findall('<h1 class="video-tt">(.*?)</h1>', detail_page_date, re.S)[0]
return video_name # 保存视频
def save(video_data, name):
with open(f'{name}.mp4', 'wb') as f:
f.write(video_data)
print(f'视频[{name}]下载成功!') def run(id):
# 拼接详情页链接并访问
detail_page_url = 'https://www.pearvideo.com/video_' + id
detail_page_data = access_page(detail_page_url).text
# 获取视频名称和视频链接
video_name = get_video_name(detail_page_data)
video_url = get_video_url(detail_page_data)
# 访问视频链接获取视频数据
video_data = access_page(video_url).content
# 保存视频数据
save(video_data, video_name) if __name__ == '__main__': homepage_data = access_page('https://www.pearvideo.com/').text
id_list = get_video_id(homepage_data) # 多线程爬取
for id in id_list:
t = Thread(target=run, args=(id,))
t.start()

Python3 并发编程4的更多相关文章

  1. Python3 并发编程3

    目录 GIL全局解释器锁 基本概念 多线程的作用 死锁现象 递归锁 信号量 线程队列 GIL全局解释器锁 基本概念 global interpreter lock 全局解释器锁 GIL不是Python ...

  2. Python3 并发编程小练习

    实现基于TCP协议套接字,服务端实现接收客户端的连接并发 # server.py import socket from threading import Thread server = socket. ...

  3. Python3 并发编程2

    目录 进程互斥锁 基本概念 互斥锁的使用 IPC 基本概念 队列 生产者消费者模型 基本概念 代码实现 线程 基本概念 创建线程 线程互斥锁 进程互斥锁 基本概念 临界资源: 一次仅允许一个进程使用的 ...

  4. Python3 并发编程1

    目录 操作系统发展 穿孔卡片 批处理 多道技术(单核) 并发与并行 进程 程序与进程 进程调度 进程的三个状态 同步和异步 阻塞与非阻塞 僵尸进程与孤儿进程 守护进程 Python中的进程操作 Pro ...

  5. Python3 与 C# 并发编程之~ 进程篇

      上次说了很多Linux下进程相关知识,这边不再复述,下面来说说Python的并发编程,如有错误欢迎提出- 如果遇到听不懂的可以看上一次的文章:https://www.cnblogs.com/dot ...

  6. Python3 与 C# 并发编程之~ 协程篇

      3.协程篇¶ 去年微信公众号就陆陆续续发布了,我一直以为博客也汇总同步了,这几天有朋友说一直没找到,遂发现,的确是漏了,所以补上一篇 在线预览:https://github.lesschina.c ...

  7. Python3 与 C# 并发编程之~进程先导篇

      在线预览:http://github.lesschina.com/python/base/concurrency/1.并发编程-进程先导篇.html Python3 与 C# 并发编程之- 进程篇 ...

  8. Python3 与 C# 并发编程之~ 线程篇

      2.线程篇¶ 在线预览:https://github.lesschina.com/python/base/concurrency/3.并发编程-线程篇.html 示例代码:https://gith ...

  9. asyncio:python3未来并发编程主流、充满野心的模块

    介绍 asyncio是Python在3.5中正式引入的标准库,这是Python未来的并发编程的主流,非常重要的一个模块.有一个web框架叫sanic,就是基于asyncio,语法和flask类似,使用 ...

随机推荐

  1. ThreadLocal深度解析和应用示例

    开篇明意 ThreadLocal是JDK包提供的线程本地变量,如果创建了ThreadLocal<T>变量,那么访问这个变量的每个线程都会有这个变量的一个副本,在实际多线程操作的时候,操作的 ...

  2. Python3安装mysql模块

    pip3 install mysql 1.错误1 原因:在 Python 3.x 版本后,ConfigParser.py 已经更名为 configparser.py 所以出错! 解决,将模块cp一份为 ...

  3. react路由的动态传参

    ① 定义规则 ②传值 ③获取传过来的值

  4. QTabWidget 头部背景色设置和QTabWidget 样式设置

    1.问题:QTabWiget的头部背景色通过设置background-color属性没有生效,网上找了很多方法,也不生效. 2.解决办法:在Qt Designer中将autoFillBackgroun ...

  5. PostGIS 查看表属性(字段、类型、是否为空)

     SELECT                a.attnum,                a.attname AS field,                t.typname AS type ...

  6. 小程序api的promise封装

    微信小程序和支付宝小程序的api封装方法是一样的,都是外部新建一个js,使用module.exports导出,要注意的是,最好使用post请求,虽然get请求没什么不好,主要是好修改.这里使用的MD5 ...

  7. nginx支持https配置

    nginx证书 nginx.conf配置.

  8. 【论文阅读】TextSnake: A Flexible Representation for Detecting Text of Arbitrary Shapes

    TextSnake: A Flexible Representation for Detecting Text of Arbitrary Shapes ECCV2018 北京大学.face++ 思路: ...

  9. (四)OpenStack---M版---双节点搭建---Glance安装和配置

    ↓↓↓↓↓↓↓↓视频已上线B站↓↓↓↓↓↓↓↓ >>>>>>传送门 1.创建glance数据库 2.获得 admin 凭证来获取只有管理员能执行的命令的访问权限 3 ...

  10. Java多线程面试题:线程锁+线程池+线程同步等

    1.并发编程三要素? 1)原子性 原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行. 2)可见性 可见性指多个线程操作一个共享变量时,其中一个线程对变量 ...