Python 并发简介

  • 多线程:threading,利用CPU和IO可以同时执行的原理,让CPU不会干巴巴的等待IO完成。

  • 多进程:multiprocessing,利用多核CPU的能力,真正并行执行任务。

  • 异步IO:asyncio,在单线程利用CPU和IO同时执行的原理,实现函数异步执行。

  • 使用 Lock对资源加锁,防止冲突访问

  • 使用Queue实现不同线程、进程之间的数据通信,实现生产者-消费者模式

  • 使用线程池Pool、进程池Pool,简化线程、进程的任务提交、等待结束、获取结果

多线程、多进程、多协程对比

  • 多进程Process(multiprocessing):

    优点:可以利用多核CPU并行计算

    缺点:占用资源最多、可启动数目比线程少

    适用于:CPU密集型计算

  • 多线程Thread(threading):
    优点:相比进程,更轻量级、占用资源少
    缺点: 1. 相比进程:多线程只能并发执行,不能利用多CPU(GIL)(python多线程中只能使用单CPU)

       2. 相比协程:启动数目有限制,占用内存资源,有线程切换开销
    

    适用于:IO密集型计算、同时运行的任务数目要求不多

  • 多协程Corotine(asyncio):

    优点:内存开销最少、启动协程数量最多

    缺点:支持的库有限制、代码实现复杂

    适用于:IO密集型计算、需要超多任务运行、但有现成的库支持的场景

IO(读写内存、发送、网络等)

关系:进程 > 线程 > 协程,一个进程中可以启动多个线程,一个线程中可以启动多个协程。

GIL

python速度慢的原因

  1. 动态类型语言,边解释边执行
  2. GIL,无法利用多核CPU并发执行

GIL

同步线程的一种机制,使得任何时刻仅有一个线程在执行。在多核心处理器上,使用 GIL 的解释器也只允许同一时间执行一个线程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jTXRZMgJ-1655734406988)(file:///D:\app\QQ\My_FILE\676221979\Image\Group2\N([J\N([JRTM]T]3G8P}_B5`S[18.png)]![img]

为什么有GIL这个东西?

简而言之:python设计初期,为了规避并发问题引入了GIL,现在想去除却去不掉

怎么规避GIL带来的限制?

  1. 多线程threading机制依然是有用的,用于IO密集型计算

    因为在IO期间,线程会释放GIL,实现CPU和IO并行,因此多线程用于IO密集型计算依然可以大幅提升速度,

    但是多线程用于CPU密集型计算时,只会更加拖慢速度。

  2. 使用multiprocessing的多进程机制实现并行计算、利用多核CPU优势

    为了应对GIL的问题,python提供了multiprocessing

多线程编程

应用于IO密集型计算,比如几乎所有的网络后台服务、网络爬虫

引入模块

  • from threading import Thread
    

新建、启动、等待结束

  • t=Thread(target=func, args=(100, ))
    t.start()
    t.join()
    

数据通信

  • import queue
    q = queue.Queue()
    q.put(item)
    item = q.get()
    

线程安全加锁

  • from threading import Lock
    lock = Lock()
    with lock:
    

    RLock和Lock的区别:

    RLock支持嵌套锁,Lock只支持锁一次解一次,不支持嵌套锁。RLock又叫递归锁,Lock又叫互斥锁。如果Lock锁上没有解锁,再锁上一次,会造成死锁。死锁另外一种情况是由于竞争资源或由于彼此通信而造成阻塞的现象。

    eg:两个线程函数func1和func2,分别被lock1和lock2锁上,在func1里(lock1未解锁)再用lock2上锁,在func2里在用lock1上锁.

信号量限制并发

  • from threading import Semaphore
    semaphre = Semaphore(10)
    with semaphre:
    

线程池

  1. 线程池的原理

  2. 使用线程池的好处

    1. 提升性能:因为减去了大量新建、终止线程的开销,重用了线程资源
    2. 适用场景:适合处理突发性大量请求或者需要大量线程完成任务、但实际任务处理时间短
    3. 防御功能:能有效避免系统因为创建线程过多,而导致系统符合过大相应变慢等问题
    4. 代码优势:使用线程池的语法比自己新建线程、执行线程更加简洁
  3. ThreadPoolExecutor的使用语法

    1. from concurrent.futures import ThreadPoolExecutor
      with ThreadPoolExecutor() as pool:results = pool.map(func, args)# args 对应着results
      
    2. future = pool.submit(func, 1)
      # 一个一个执行,一个arg对应一future
      futures = [pool.submit(func, arg)  for arg in args]
      # 两种遍历方式
      # 1
      for future in futures:print(future.result())
      # 2
      for future in as_completed(futures):print(future.result())
      
  4. 使用线程池改造爬虫

使用线程池在Web服务中实现加速

多进程编程

如果遇到了 CPU密集型计算,线程自动切换反而变成了负担,多线程反而会降低执行速度,multiprocessing模块就是python为了解决GIL缺陷引入的模块,原理就是用多进程在多CPU上并发执行。

语法 多线程 多进程
引入模块 from threading import Thread from multiprcessing import Prcoess
新建
启动
等待结束
t = Thread(target=func, args=(100,))
t.start
t.join()
p = Process(target=func, args=('bob',))
p.start
p.join()
数据通信 import queue
q = queue.Queue()
q.put(item)
item = q.get()
from multiprcessing import Queue
q = Queue()
q.put([42, None, 'hello']])
item = q.get()
安全加锁 from threading import Lock
lock = Lock()
with lock:
pass
from multiprocessing import Lock
lock = Lock()
with lock:
pass
池化技术 from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor() as pool:
# 方法1
results = pool.map(func, args)
# args 对应着results
# 方法2
future = pool.submit(func, 1)
result = future.result()
from concurrent.futures import ProcessPoolExecutor
with ProcessPoolExecutor() as pool:
# 方法1
results = pool.map(func, args)
# args 对应着results
# 方法2
future = pool.submit(func, 1)
result = future.result()

进程间通信

进程间相互独立

  1. ​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RS9b1qGP-1655820951762)(C:\Users\han\Desktop$QFO8S6I}%)]65KLU}{H]$WY.jpg)
  2. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CzofiY84-1655820951763)(C:\Users\han\Desktop\U_E)]14A88XMZ]C0}%Y_HL0P.jpg)
  3. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dyujjB7J-1655820951763)(C:\Users\han\Desktop~NA

Python 并发简介

  • 多线程:threading,利用CPU和IO可以同时执行的原理,让CPU不会干巴巴的等待IO完成。

  • 多进程:multiprocessing,利用多核CPU的能力,真正并行执行任务。

  • 异步IO:asyncio,在单线程利用CPU和IO同时执行的原理,实现函数异步执行。

  • 使用 Lock对资源加锁,防止冲突访问

  • 使用Queue实现不同线程、进程之间的数据通信,实现生产者-消费者模式

  • 使用线程池Pool、进程池Pool,简化线程、进程的任务提交、等待结束、获取结果

多线程、多进程、多协程对比

  • 多进程Process(multiprocessing):

    优点:可以利用多核CPU并行计算

    缺点:占用资源最多、可启动数目比线程少

    适用于:CPU密集型计算

  • 多线程Thread(threading):
    优点:相比进程,更轻量级、占用资源少
    缺点: 1. 相比进程:多线程只能并发执行,不能利用多CPU(GIL)(python多线程中只能使用单CPU)

       2. 相比协程:启动数目有限制,占用内存资源,有线程切换开销
    

    适用于:IO密集型计算、同时运行的任务数目要求不多

  • 多协程Corotine(asyncio):

    优点:内存开销最少、启动协程数量最多

    缺点:支持的库有限制、代码实现复杂

    适用于:IO密集型计算、需要超多任务运行、但有现成的库支持的场景

IO(读写内存、发送、网络等)

关系:进程 > 线程 > 协程,一个进程中可以启动多个线程,一个线程中可以启动多个协程。

GIL

python速度慢的原因

  1. 动态类型语言,边解释边执行
  2. GIL,无法利用多核CPU并发执行

GIL

同步线程的一种机制,使得任何时刻仅有一个线程在执行。在多核心处理器上,使用 GIL 的解释器也只允许同一时间执行一个线程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jTXRZMgJ-1655734406988)(file:///D:\app\QQ\My_FILE\676221979\Image\Group2\N([J\N([JRTM]T]3G8P}_B5`S[18.png)]![img]

为什么有GIL这个东西?

简而言之:python设计初期,为了规避并发问题引入了GIL,现在想去除却去不掉

怎么规避GIL带来的限制?

  1. 多线程threading机制依然是有用的,用于IO密集型计算

    因为在IO期间,线程会释放GIL,实现CPU和IO并行,因此多线程用于IO密集型计算依然可以大幅提升速度,

    但是多线程用于CPU密集型计算时,只会更加拖慢速度。

  2. 使用multiprocessing的多进程机制实现并行计算、利用多核CPU优势

    为了应对GIL的问题,python提供了multiprocessing

多线程编程

应用于IO密集型计算,比如几乎所有的网络后台服务、网络爬虫

引入模块

  • from threading import Thread
    

新建、启动、等待结束

  • t=Thread(target=func, args=(100, ))
    t.start()
    t.join()
    

数据通信

  • import queue
    q = queue.Queue()
    q.put(item)
    item = q.get()
    

线程安全加锁

  • from threading import Lock
    lock = Lock()
    with lock:
    

    RLock和Lock的区别:

    RLock支持嵌套锁,Lock只支持锁一次解一次,不支持嵌套锁。RLock又叫递归锁,Lock又叫互斥锁。如果Lock锁上没有解锁,再锁上一次,会造成死锁。死锁另外一种情况是由于竞争资源或由于彼此通信而造成阻塞的现象。

    eg:两个线程函数func1和func2,分别被lock1和lock2锁上,在func1里(lock1未解锁)再用lock2上锁,在func2里在用lock1上锁.

信号量限制并发

  • from threading import Semaphore
    semaphre = Semaphore(10)
    with semaphre:
    

线程池

  1. 线程池的原理

  2. 使用线程池的好处

    1. 提升性能:因为减去了大量新建、终止线程的开销,重用了线程资源
    2. 适用场景:适合处理突发性大量请求或者需要大量线程完成任务、但实际任务处理时间短
    3. 防御功能:能有效避免系统因为创建线程过多,而导致系统符合过大相应变慢等问题
    4. 代码优势:使用线程池的语法比自己新建线程、执行线程更加简洁
  3. ThreadPoolExecutor的使用语法

    1. from concurrent.futures import ThreadPoolExecutor
      with ThreadPoolExecutor() as pool:results = pool.map(func, args)# args 对应着results
      
    2. future = pool.submit(func, 1)
      # 一个一个执行,一个arg对应一future
      futures = [pool.submit(func, arg)  for arg in args]
      # 两种遍历方式
      # 1
      for future in futures:print(future.result())
      # 2
      for future in as_completed(futures):print(future.result())
      
  4. 使用线程池改造爬虫

使用线程池在Web服务中实现加速

多进程编程

如果遇到了 CPU密集型计算,线程自动切换反而变成了负担,多线程反而会降低执行速度,multiprocessing模块就是python为了解决GIL缺陷引入的模块,原理就是用多进程在多CPU上并发执行。

语法 多线程 多进程
引入模块 from threading import Thread from multiprcessing import Prcoess
新建
启动
等待结束
t = Thread(target=func, args=(100,))
t.start
t.join()
p = Process(target=func, args=('bob',))
p.start
p.join()
数据通信 import queue
q = queue.Queue()
q.put(item)
item = q.get()
from multiprcessing import Queue
q = Queue()
q.put([42, None, 'hello']])
item = q.get()
安全加锁 from threading import Lock
lock = Lock()
with lock:
pass
from multiprocessing import Lock
lock = Lock()
with lock:
pass
池化技术 from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor() as pool:
# 方法1
results = pool.map(func, args)
# args 对应着results
# 方法2
future = pool.submit(func, 1)
result = future.result()
from concurrent.futures import ProcessPoolExecutor
with ProcessPoolExecutor() as pool:
# 方法1
results = pool.map(func, args)
# args 对应着results
# 方法2
future = pool.submit(func, 1)
result = future.result()

进程间通信

进程间相互独立

线程池里,multiporcessing.RLock() 不可使用

使用: manager = multiprocessing.Manager()

lock = manager.RLock()

RLock 可以多次使用多次释放、递归锁

Lock

Python 并发简介(多线程、多进程)相关推荐

  1. python 并发编程 多线程 目录

    线程理论 python 并发编程 多线程 开启线程的两种方式 python 并发编程 多线程与多进程的区别 python 并发编程 多线程 Thread对象的其他属性或方法 python 并发编程 多 ...

  2. 【Python成长之路】python并发学习:多进程与多线程的用法及场景介绍

    刚开始学习Python 并发查询或者并发读写时,看到大神们说,多线程是python的鸡肋,要学就学多进程.好吧,我连多线程怎么写都不知道呢. 因此,就写了以下的示例代码.代码目的是将test.txt文 ...

  3. Python并发编程之多进程(一)

    一.什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 进程是资源分配的基本单位 进程有:代码段,数据段,进程控制块(PCB)组成 二.进程与程序的区别 程序仅仅只是一堆代 ...

  4. 并发并行多线程多进程协程

    并行(Parallelism) 并行是说同一时刻做很多操作.多进程是实现并行的有效方法.因为它可以将许多任务分配到计算机的多个核心上.多进程很适合计算密集型的任务,因为它充分地利用了多个CPU. 多进 ...

  5. python并发编程之多进程、多线程、异步和协程

    转载 自 tyomcat: https://www.cnblogs.com/tyomcat/p/5486827.html 一.多线程 多线程就是允许一个进程内存在多个控制权,以便让多个函数同时处于激活 ...

  6. python并发编程之多进程理论部分

    阅读目录 一 什么是进程 二 进程与程序的区别 三 并发与并行 四 同步\异步and阻塞\非阻塞(重点) 五 进程的创建(了解) 六 进程的终止(了解) 七 进程的层次结构 八 进程的状态 九 进程并 ...

  7. Python并发编程之多进程(二)

    十.进程同步 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的, 而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理 ---------- ...

  8. python并发编程之多进程理论知识

    一 什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 举例(单核+多道,实现多个进程的并发执行): egon在一个时间段内有很多任务要做:python备课的任务,写书的任 ...

  9. Python并发编程:多进程-守护进程

    一 守护进程 主进程创建子进程,然后将该进程设置成守护自己的进程,守护进程就好比皇帝身边的老太监,皇帝已死老太监就跟着殉葬了. 关于守护进程需要强调两点: 其一:守护进程会在主进程代码执行结束后就终止 ...

  10. python 并发编程 多线程 守护线程

    做完工作这个进程就应该被销毁 单线程情况: 一个进程 ,默认有一个主线程 ,这个主线程执行完代码后 ,就应该自动销毁.然后进程也销毁. 多线程情况: 主线程代表进程结束 一个进程可以开多个线程,默认开 ...

最新文章

  1. 解密美国五角大楼人工智能中心
  2. Win7 下安装VirtualBox 没有Ubuntu 64bit 选项问题
  3. JAVA学习笔记--初始化与清理
  4. linux rm命令详解
  5. 电子商务计算机网络安全技术教案,网络安全技术教案.pdf
  6. 【探索PowerShell 】【十二】筛选器 - Filters
  7. java格式化数字 NumberFormat及DecimalFormat
  8. STELLA—系统动力学仿真软件 System Dynamics仿真
  9. win10磁盘占用率过高解决办法
  10. python plt 画图
  11. 【Linux】无法读取/挂载U盘
  12. 非常有意思的网页版在线PS
  13. 005. C++智能指针
  14. 关于MFC程序中隐藏任务栏图标的问题
  15. SpringBoot配置多数据库的数据源
  16. 左移寄存器vhdl_基于VHDL的移位寄存器设计
  17. FBI树--字符二叉树
  18. 搜索引擎快捷导航:一个简单的chrome插件(教程)
  19. 物联网-业务数据智能管理应用设计
  20. ADS系列 – 低噪声放大器(LNA)模型下载安装及 LNA仿真设计

热门文章

  1. 几款对于学习前端比较好用的软件或网址
  2. Scratch妙笔生花
  3. 少儿编程scratch(源码)
  4. matlab猜数字游戏程序,matlab 猜数字小游戏
  5. linux 如何看图软件,深度看图(linux看图软件) v1.2 官方最新版
  6. Saas项目和Pass项目
  7. 红外非均匀矫正matlab实现,一种红外图像非均匀性校正方法与流程
  8. qgis经纬度_QGIS中文系列教程
  9. 环境影响评价知识点整理
  10. 【ANSYS命令流】为什么是命令流?