マルチタスクの概念
複数のタスクを同時に実行する
マルチタスクの利点
最大のメリットはCPUリソースを最大限に活用し、プログラムの実行効率を向上させることです。
GIL ロック (グローバル解釈ロック)
プロセス内の 1 つのスレッドのみが CPU によって同時に呼び出されるようにすることで、スレッドの安全性の問題を解決できます。スレッド ロックとプロセス ロックがあります。
Rlock: 再帰的ロック
ロック: 同期ロック
マルチタスクの 2 つの表現
同時実行性: 一定期間内に複数のタスクを交互に実行します。
たとえば、シングルコア CPU が複数のタスクを処理する場合、オペレーティング システムは順番に各タスクを交互に実行します。
並列処理: 複数のタスクを一定期間にわたって真に同時に一緒に実行すること
たとえば、マルチコア CPU がマルチタスクを処理できるように、オペレーティング システムは CPU の各コアが実行するタスクを配置します。複数のコアは実際に複数のタスクを同時に実行できます。ここで注意しなければならないのは、マルチコア CPU は複数のタスクを並列に実行し、複数のタスクは常に一緒に実行されるということです。
プログラムにマルチタスクを実装する方法
プロセス
プロセスの概念
プロセスはリソース割り当ての最小単位です。オペレーティング システムによるリソース割り当てとスケジューリングの基本単位です。一般的な理解: 実行中のプログラムはプロセスです。たとえば、QQ WeChat の実行など、それらはすべて 1 つのプロセスです。
複数のプロセスの役割
CPU リソースを最大限に活用し、プログラムの実行効率を向上させ、プロセスを互いに分離します。
プロセス間のデータ共有
プロセスはリソース割り当ての最小単位であり、各プロセスは独自の独立したデータを保持し、共有しません。彼らの間で共有したい場合は、特別なものを利用して共有することができます。
マルチタスクを完了するマルチプロセス
プロセスを作成するための 3 つのステップ
プロセスクラスを通じてプロセスオブジェクトを作成する
プロセスオブジェクト=multiprocessing.Process(ターゲット=タスク名)
プロセスの作成と起動のためのコード
プロセスはパラメータを指定してタスクを実行します
target パラメータに加えて、他に 2 つのパラメータがあります
パラメータ引数 (タプル形式)。タプルの順序はタスクのパラメータの順序です。
パラメータ kwargs (辞書モード)、パラメータ辞書のキーはパラメータ名と一致している必要があります
プロセス番号を取得する
プロセス番号の役割:プログラム内のプロセス数が増加した場合、メインプロセスとサブプロセスの区別がつかず、異なるサブプロセスが存在すると効率的なプロセス管理が行えません。実際、管理を容易にするために、各プロセスにはすべて独自の番号が付いています。
現在のプロセスの番号を取得する
os.getpid()
現在のプロセスの親プロセスの番号を取得します
os.getppid()
一般的な方法
p.start():当前进程准备就绪,等待CPU调度(工作单元其实是进程中的线程)
p.join():等待当前进程的任务执行完毕后再向下继续进行
p.setFaemon(布尔值):守护进程(必须放在start之前)
p.setFaemon(布尔值):设置为守护进程,主进程执行完毕后,子进程也会自动关闭
p.setFaemon(布尔值):设置为非守护进程,主进程等待子进程,子进程执行完毕后,主进程才会结束(默认)
p.name=“xxx”:进程的名称和设置
multiprocessing.current_process().name:获取当前执行代码的进程名
os.getpid():获取当前进程id
os.getppid():获取当前进程父进程的id
len(threading.enumerate()):获取当前进程中的线程个数
multiprocessing.cpu_count():获取当前cpu个数
进程的注意点
1)主进程会等待所有的子进程执行结束再结束
举例:虽然“主进程执行完成了哦”可能夹在“工作中...”,但是它输出后函数并没有结束,子进程还在执行,待子进程结束后,函数才终止
2)设置守护主进程
举例:加了这行代码后,一旦输出“主进程完成了哦”,就代表函数的终止,子进程会自动销毁,不会在执行
进程池
进程不是开得越多越好,线程池里的线程个数要适量
不建议:无限制的创建进程
建议:使用进程池
线程
线程的概念
线程是程序执行的最小单位,实际上进程只负责分配资源,而利用这些资源执行程序的是线程,也就说进程是线程的容器,一个进程中最少有一个线程来负责执行程序。同时线程自己不拥有系统资源,只需要一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
为什么使用线程
进程是分配资源的最小单位,一旦创建一个进程就会分配一定的资源,就像跟两个人聊QQ就需要打开两个QQ软件一样是比较浪费资源
但是线程自己不拥有系统资源,只需要一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源,这就像通过一个QQ软件(一个进程)打开两个窗口(两个线程)跟两个人聊天一样,实现多任务的同时也节省了资源。
多线程的作用
相比进程,实现多任务的同时也节省了资源
多线程完成多任务
线程的三步创建步骤
通过进程类创建线程对象
线程对象=threading.Thread(target=任务名)
线程创建与启动的代码
线程执行带有参数的任务
除了target参数还有另外两种参数
参数args(以元组方式),其中元组的顺序就是任务的参数的顺序
参数kwargs(以字典方式),其中传参字典的key一定要和参数名保持一致
主线程和子线程的结束顺序
主线程会等待所有的子线程结束后再结束
设置守护主线程:可以让主线程不等待子线程执行完成
线程间的执行程序
线程之间是无序的,是由CPU调度决定某个线程先执行的
获取当前的线程信息
常见方法
t.start():当前线程准备就绪(等待CPU调度,具体时间由CPU来决定)
t.join():等待当前线程的任务执行完毕后再向下继续进行
t.setFaemon(布尔值):守护线程(必须放在start之前)
t.setFaemon(布尔值):设置为守护线程,主线程执行完毕后,子线程也会自动关闭
t.setFaemon(布尔值):设置为非守护线程,主线程等待子线程子线程执行完毕后,主线程才会结束(默认)
t.setName():线程的名称和设置
t.threading.current_thread().getName():获取当前执行代码的线程名
线程池
线程不是开得越多越好,开的多了可能会导致系统的性能更低了。
不建议:无限制的创建线程
建议:使用线程池
进程和线程对比
关系对比
线程是依托在进程里面的,没有进程就没有线程
一个进程默认提供一条线程,进程可以创建多个线程
区别对比
创建进程的资源开销要比创建线程的资源开销大
进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位
线程不能够独立运行,必须依托在进程中
优缺点对比
进程优缺点
优点:可以使用多核
缺点:资源开销大
线程优缺点
优点:资源开销小
缺点,不能使用多核
应用场景
如果每个子进程执行需要消耗的时间非常短(执行+1操作等),这不必使用多进程,因为进程的上下文切换(启动关闭)也会耗费资源
使用多进程往往是用来处理CPU密集型(科学计算)的需求,如果是IO密集型(文件读取,爬虫等)则可以使用多线程去处理
想利用计算机的多核优势,让CPU同时处理一些任务,适合用多进程开发(即使资源开销大)
不利用计算机的多核优势,适用于多线程开发