从操作系统角度
操作系统处理任务, 调度单位是进程和线程.
进程: 表示一个程序的执行活动 (打开程序, 读写程序数据, 关闭程序)
线程: 执行某个程序时, 该进程调度的最小执行单位 (执行功能 1, 执行功能 2)
一个程序至少有一个进程, 一个进程至少有一个线程.
并行:
需要处理的任务数 == CPU 核心数量
两个任务, 两个核心
任务 1:-------------
任务 2:-------------
并发:
需要处理的任务数 > CPU 核心数量
三个任务, 一个核心
任务 1: ----- ------
任务 2: ------
任务 3: ------
从程序角度
多进程, 多线程
表示当前程序可以同时执行多个任务
进程和线程都是由操作系统调度完成.
进程:
每个进程都有自己独立的内存空间, 不同进程之间的内存空间不能共享.
不同进程之间的通信由 操作系统 完成.
不同进程之间的通信效率低下, 切换开销大.
线程:
一个进程下可以有多个线程, 同一个进程内的线程可以共享内存空间.
不同线程之间的通信 有进程 管理.
不同线程之间的通信效率高, 切换开销小.
互斥锁:
共享意味着多个线程的竞争, 会导致不安全问题.
为了保护内存空间的数据不被多个线程同时读写, 导致数据隐患, 于是诞生了 "互斥锁".
"互斥锁": 一种安全有序的让多个线程访问进程内存空间的机制.
当一个线程在访问进程内存空间时, 互斥锁可以防止其他线程访问
解释型语言: 执行程序时, 解释器按行执行程序内容, 执行时检查问题.
编译型语言: 通过编译器将程序编译为一个可执行文件, 执行前检查问题.
Python 中的多线程:
GIL(全局解释器锁): 同一时刻只能有一个线程在运行.
坏处: 多线程不能充分利用多核 CPU 资源.
好处: 从根本上杜绝了多线程访问内存空间的安全问题.
Python 的多线程不适合并行, 但非常适合并发.
Python 的多线程在遇到 IO 阻塞函数执行, 会自动释放 GIL, 让后面的线程执行任务.
如果没有 IO 操作, 那么解释器会每隔 100 次操作后, 强制释放 GIL, 让后面的线程执行.
- import sys
- sys.getcheckinterval()
多进程:
适用于密集 CPU 任务, 可以充分调度 CPU 资源 (大量的并行运算).
multiprocessing
缺点: 不适用于需要大量数据通信和多次切换的场景, 因为进程之间通信和切换成本高.
多线程:
适用于密集 IO 任务 (网络 IO, 磁盘 IO, 数据库 IO), 在 IO 阻塞时可以切换线程执行.
threading.Thread,multiprocessing.dummy
缺点: 同一个 CPU 时间片只能执行一个任务, 不能做到并行, 只能做到并发.
优点: 线程之间切换和通信非常方便, 开销小.
协程:
由程序员自行编写调度功能, 切换协程就好比切换一个函数, 几乎没有切换开销.
特点是在单线程上执行多个任务, 调度由程序员控制, 不经过操作系统, 所以没有进程线程的切换开销, 也不需要处理锁.
- gevent
- monkey.patch_all()
monkey 的作用是将 Python 底层的网络库 socket,select 自动打个补丁, 程序在遇到网络 IO 阻塞时, 可以自动切换协程工作.(该补丁不适用于本地 IO)
优点: 协程任务是基于用户的, 不经过操作系统, 执行效率极高.
缺点: 单线程执行, 不能处理 CPU 密集任务, 和密集本地 IO 任务.
来源: https://www.cnblogs.com/kangyuqi/p/9323789.html