概念介绍
串行
一个CPU上,按顺序完成多个任务
并行
任务数少于CPU数,多个任务在多个不同CPU上执行。(多个任务一起执行,且可以保证每个CPU只执行一个任务)
并发
一个CPU采用时间片管理方式,多个任务在同一个CPU上交替执行,想象中是多个任务一起执行,实际上总有一些任务没有执行。
进程
进程(Process)是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。进程是操作系统分配资源的最小单位。对于操作系统来说,打开一个任务就是一个进程,比如,打开一个浏览器就是启动一个浏览器进程、打开记事本就是启动一个记事本进程。
线程
线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。比如打开微信就是一个启动微信进程,但是微信可以同时进行打字聊天、视频聊天、朋友圈等等。在一个进程内部需要同时运行多个子任务,这些子任务就成为线程。
协程
比如,一条生产线就是一个进程,这条生产线上有5个工人,每个工人就相当于一个线程,在生产过程中,某一个工人需要的零件还没到,这时他就没事做,他可以去帮助其他工人做事,这就是协程。即如果一个线程等待某些条件,可以充分利用这个时间去做其它事情,这就是:协程方式。
由上图可以看出:
进程:拥有独立的堆和栈,不需要共享堆也不需要共享栈,由操作系统调度,切换需要的资源很大,效率低;
线程:拥有独立的栈和共享的堆,由操作系统调度,切换需要的资源一般,效率也一般(不考虑GIL的情况);
协程:拥有独立的栈和共享的堆,由程序员在协程的代码里显示调度,切换任务资源很小,效率高
线程、进程、协程区别(上图可以看出)
1.线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;
2.一个进程可以包含多个线程,线程是一个进程中代码的不同执行路线,一个线程可以包含多个协程;
3.进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号),某进程内的线程在其它进程不可见;
4.调度和切换:线程上下文切换比进程上下文切换要快得多。
同步和异步
同步和异步强调的是消息通信机制。
同步(synchronous):A调用B,等B返回结果后,A继续执行
异步(asynchronous):A调用B,A继续执行,不用等B的返回结果;B有结果了,通知A,A再做处理。
线程的创建方式
Python的标准库提供了两个模块: _thread 和threading , _thread 是低级模块, threading 是高级模块,对_thread 进行了封装。绝大多数情况下,我们只需要使用threading 这个高级模块。
线程的创建可以通过分为两种方式:
1. 方法包装
2. 类包装
线程的执行统一通过start() 方法
1.方法包装
from threading import Thread
from time import sleep
def func1(name):
print(f"线程{name},start")
for i in range(3):
print(f'线程{name}:{i}')
sleep(1)
print(f"线程{name},end")
if __name__ == '__main__':
print('主线程,start')
# 创建线程
t1 = Thread(target=func1, args=("t1",))
t2 = Thread(target=func1, args=("t2",))
# 启动线程
t1.start()
t2.start()
print('主线程, end')
2. 类包装
from threading import Thread
from time import sleep
class MyThread(Thread):
def __init__(self, name):
Thread.__init__(self)
self.name = name
def run(self):
# 重写run方法
print(f"线程{self.name},start")
for i in range(3):
print(f'线程{self.name}:{i}')
sleep(1)
print(f"线程{self.name},end")
if __name__ == '__main__':
print('主线程, start')
thread1 = MyThread('t1')
thread2 = MyThread('t2')
thread1.start()
thread2.start()
print('主线程, end')