多任务:进程、线程、协程
进程 系统进行资源分配和调度的基本单位
线程 系统独立调度和分派的基本单位 ,是CPU调度的最小单位(程序执行流的最小单元)
进程切换需要的资源最大,效率最低
线程切换需要的资源一般,效率一般(当然在不考虑GIL的情况下)
协程切换任务资源很小,效率高,协程又称微线程
多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中,所以是并发。
并发:当多个线程在运行时,如果系统只有一个CPU,它会合理分配给多个线程去执行任务,执行快的多分配,执行慢的少分配。
并行:当系统有多个CPU时, 线程会分配到不同CPU,互不抢占资源,可以同时进行。
并发和并行最大的区别就在于,是否同时。
多进程:在系统同时执行多个不同的任务
多线程:在单一程序中同时完成多个不同的任务
区别点
一个程序至少有一个进程 一个进程至少有一个线程
进程不共享全局变量,线程可以共享全局变量
线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享
多线程(共享全局变量)
from threading import Thread
import time
def work1(nums):
nums.append(44)
print("----in work1---",nums)
def work2(nums):
#延时一会,保证t1线程中的事情做完
time.sleep(1)
print("----in work2---",nums)
g_nums = [11,22,33]
t1 = Thread(target=work1, args=(g_nums,))
t1.start()
t2 = Thread(target=work2, args=(g_nums,))
t2.start()
结论
在一个线程内对所有线程共享全局变量,很方便多个线程共享数据,但是如果修改全局变量会造成多线程之间的混乱(即线程非安全)
如果多个线程同时对一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确。
互斥锁
目的:当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
好处:确保了某段关键代码只能由一个线程从头到尾完整地执行
坏处:阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了,由于可以存在多个所锁,不同的线程持有不同的锁,并视图获取对方持有的锁时,可能会造成死锁
# 创建锁
mutex = threading.Lock()
# 锁定
mutex.acquire()
# 释放
mutex.release()
避免死锁
1、程序设计时尽量避免(银行家算法)
2、添加超时时间
进程
创建进程的方式一:
import time from multiprocessing import Process def test(): """子进程单独执行的代码""" while True: print('----test----') time.sleep(1) # 睡眠一秒钟 if __name__ == '__main__': p = Process(target=test) # 把函数的名字传到进程中 target会指定一个函数的引用 p.start() # 开启进程 当这句话执行时才创建了一个进程 # 主进程执行代码 while True: print('----main----') time.sleep(1)
总结:
1.通过额外创建一个进程,可以实现多任务使用进程实现多任务的流程:
2.创建一个Process对象,且在创建时通过target指定一个函数的引用
3.当调用start时,会真正的创建一个子进程
Process创建的实例对象的常用办法:
1.start():启动子进程实例(创建子进程)
2.is_live():判断子进程是否还在活着
3.join([timeout]):是否等待子进程执行结束,或等待多少秒
terminate():不管任务是否完成,立即终止子进程
创建进程的方式二:
import time
from multiprocessing import Process
# 方法二:
class MyProcess(Process):
def run(self):
while True:
print('----1----')
time.sleep(1)
if __name__ == '__main__':
p = MyProcess() # 创建一个MyProcess的对象
# 当执行到这一句话的时候 会调用p.start()方法,p会先去父类中寻找start(),然后再Process的start方法中调用run方法
p.start()
while True:
print('----main----')
time.sleep(1)