day5-进程、线程、协程
1.进程
进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础
2.进程的优点:
动态性:进程是程序的一次执行过程,是临时的,有生命期的,是动态产生,动态消亡的;
并发性:任何进程都可以同其他进行一起并发执行;
独立性:进程是系统进行资源分配和调度的一个独立单位;
结构性:进程由程序,数据和进程控制块三部分组成
3.进程缺点
a.进程的创建和销毁过程需要消耗较多的计算机资源
b.资源消耗过多
4.进程代码
import time
import multiprocessing
def dance():
while True:
print("跳舞")
time.sleep(1)
def song():
while True:
print("唱歌")
time.sleep(1)
def main():
"""一边唱歌一边跳舞"""
p1 = multiprocessing.Process(target=dance)
p2 = multiprocessing.Process(target=song)
p1.start()
p2.start()
time.sleep(3)
# 进程结束
p1.terminate()
p2.terminate()
if __name__ == '__main__':
main()
5.线程
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务,同一进程下的线程不仅共享进程资源和内存,每个线程还可有一个属于它自己的内存空间——线程栈
6.线程的优点
a.线程间切换快
b.共享数据
c.多核cpu利用率
7.线程的缺点
a.每个线程与主程序共用地址空间,受限于2GB地址空间;
b.线程之间的同步和加锁控制比较麻烦;
c.线程没有独立的空间,一个线程死掉整个进程都会挂掉
8.线程代码
import threading
import time
from time import sleep
def sing():
for i in range(3):
print("正在唱歌...%d" % i)
sleep(1)
def dance():
for i in range(3):
print("正在跳舞...%d" % i)
sleep(1)
# 子线程全部执行完 主线程才会结束 程序也就结束了
if __name__ == '__main__':
t1 = threading.Thread(target=sing)
t2 = threading.Thread(target=dance)
# 开启两个子线程
t1.start()
t2.start()
# print(t1.name)
# print(t2.name)
while True:
# 获取当前有几个线程
length = len(threading.enumerate())
print(length)
if length == 1:
break
time.sleep(0.5)
9.协程
协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)。 为啥说它是一个执行单元,因为它自带CPU上下文。这样只要在合适的时机, 我们可以把一个协程 切换到另一个协程。 只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的。
通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定
10协程的优点
a.协程是用户自己控制切换的时机,不再需要陷入系统的内核态
b.协程的执行效率非常高。因为子程序切换不是线程切换,而是由程序自身控制
c.不需要多线程的锁机制。由于只有一个线程,也不存在同时写变量的冲突,在协程中控制共享资源不需要加锁,只需要判断数据的状态,所以执行效率远高于线程 ,对于多核CPU可以使用多进程+协程来尽可能高效率地利用CPU
11.协程的缺点
a.无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
b.进行阻塞操作(如IO时)会阻塞掉整个程序
12.协程代码
import time
def work1():
while True:
print("----work1---")
yield
time.sleep(0.5)
def work2():
while True:
print("----work2---")
yield
time.sleep(0.5)
def main():
# 获取w1 w2 两个生成器对象
w1 = work1()
w2 = work2()
while True:
next(w1)
next(w2)
if __name__ == "__main__":
main()
13.进程和线程的区别
a. 一个程序中至少有一个进程,一个进程中至少有一个线程;
b. 线程的划分尺度小于进程(占有资源),使得多线程程序的并发性高;
c. 进程运行过程中拥有独立的内存空间,而线程之间共享内存,从而极大的提高了程序的运行效率
d.线程不能独立运行,必须存在于进程中
e.线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位
f.调度和切换:线程上下文切换比进程上下文切换要快得多
14.线程和协程的区别
a.一个线程可以多个协程,一个进程也可以单独拥有多个协程。
b. 线程进程都是同步机制,而协程则是异步。
c. 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。
d.线程是抢占式,而协程是非抢占式的,所以需要用户自己释放使用权来切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力。
e.协程并不是取代线程, 而且抽象于线程之上, 线程是被分割的CPU资源, 协程是组织好的代码流程, 协程需要线程来承载运行, 线程是协程的资源, 但协程不会直接使用线程, 协程直接利用的是执行器(Interceptor), 执行器可以关联任意线程或线程池, 可以使当前线程, UI线程, 或新建新程.。
f.线程是协程的资源。协程通过执行器来间接使用线程这个资源。
15.并发与并行
并发:计算机的操作系统通过时间片轮转法等算法调度交替执行不同的任务。
并行:同时执行不同的任务。
16.同步与异步
同步:是指一个进程在执行某个请求的时候,若这个请求没有执行完成,那么这个进程将会一直等待下去,直到这个请求执行完毕,才会继续执行下面的请求。
异步:是指一个进程在执行某个请求的时候,如果这个请求没有执行完毕,进程不会等待,而是继续执行下面的请求。
17.阻塞与非阻塞
阻塞:指调用函数时候当前线程被挂起
非堵塞:指调用函数时候当前线程不会被挂起,而是立即返回。
18.互斥锁
a. 线程锁保证同一时刻只有一个线程修改内存空间的同一数据,GIL保证同一时刻只有一个线程在运行。
b. 多线程同时修改同一数据,可能会导致数据最终结果不准确。
简单总结
a. 进程是资源分配的单位
b. 线程是操作系统调度的单位
c. 进程切换需要的资源很最大,效率很低
d. 线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
e. 协程切换任务资源很小,效率高
f. 多进程、多线程根据cpu核数不一样可能是并行的,但g. 是协程是在一个线程中 所以是并发