多进程:
优点:可以用多核
缺点:开销大
多线程:
优点:开销小
缺点:不能使用多核
在日常的生活中,我们用到的肯定是多核机器,所以我们只考虑多核的情况,你会说那么根据上面的优缺点,那肯定就用多进程就好了。欧克,那只是你自己的意淫而已,接下来我要解释一波了,请听好:
我们首先确定的点,就是在一个多核的机器上,进行一系列的操作,那么使用多线程好呢?还是多进程好呢?
在这个时候我要提出一个观点:就是CPU肯定是用来做计算的,这是毋庸置疑的。
ok,我们在之前的基础上,考虑两种情况:
1,计算密集的操作:我用代码来征服你们,看哪一个更好
from multiprocessing import Process import time def work(): res = 0 for i in range(11111100): res+=i if __name__ == '__main__': start = time.time() l = [] for i in range(4): p = Process(target=work) l.append(p) p.start() for j in l: j.join() end = time.time() print('%s'%(end - start)) 运行时间:1.794102430343628 #根据机子的不同可能结果也并不同
from threading import Thread import time def work(): res = 0 for i in range(11111100): res+=i if __name__ == '__main__': start = time.time() l = [] for i in range(4): T = Thread(target=work) l.append(T) T.start() for j in l: j.join() end = time.time() print('%s'%(end - start)) 结果:3.125178813934326
看结果一目了然,进程很快,你很牛逼,我来说说原理:对于多线程来说,上面已经提到,他的缺点就是无法使用多核,由于gil锁的存在,他只能一个一个的取抢锁,所以会慢,多进程则相反
2,i/o密集的操作:依旧用代码来征服你:
from threading import Thread import time def work(): time.sleep(2) if __name__ == '__main__': start = time.time() l = [] for i in range(400): p = Thread(target=work) # p = Process(target=work) l.append(p) p.start() for j in l: j.join() end = time.time() print('%s' % (end - start)) 结果:2.048117160797119
from multiprocessing import Process import time def work(): time.sleep(2) if __name__ == '__main__': start = time.time() l = [] for i in range(400): # p = Thread(target=work) p = Process(target=work) l.append(p) p.start() for j in l: j.join() end = time.time() print('%s' % (end - start)) 结果:from multiprocessing import Process from threading import Thread import time def work(): time.sleep(2) if __name__ == '__main__': start = time.time() l = [] for i in range(400): # p = Thread(target=work) p = Process(target=work) l.append(p) p.start() for j in l: j.join() end = time.time() print('%s' % (end - start)) 结果:19.68112564086914
看结果很明显:我用时间的停留模拟i/o阻塞,进程确实是并发的,但是在i/o阻塞的时候都要等着,无法运行,并且在进程创建的时候开销大,时间长,即使是并发的,我开了400个进程,机已经多出了那么多的时间,可想而知,开更多会是什么样。
应用:
计算密集 多进程 金融领域
i/o密集 多线程 爬虫 web socket
死锁 与递归锁、
所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,情况如下:
from threading import Thread,Lock import time mutexA = Lock() mutexB = Lock() class Work(Thread): def run(self): self.f1() self.f2() def f1(self): mutexA.acquire() print('%s 拿到了A锁 ' % self.name) mutexB.acquire() print('%s拿到了B锁' % self.name) mutexB.release() print('%s 释放了 B锁' % self.name) mutexA.release() print('%s 释放了 A锁' % self.name) def f2(self): mutexB.acquire() time.sleep(2) print('%s 拿到了B锁 ' % self.name) mutexA.acquire() print('%s拿到了A锁' % self.name) mutexA.release() print('%s 释放了 A锁' % self.name) mutexB.release() print('%s 释放了 B锁' % self.name) if __name__ == '__main__': for i in range(5): t = Work() t.start()
解决方法:
递归锁:Rlock
Rlock内部有一个count 初始为0 ,锁一下加1,释放了就减一。
from threading import Thread,RLock import time mutexA = mutexB = RLock() class Work(Thread): def run(self): self.f1() self.f2() def f1(self): mutexA.acquire() print('%s 拿到了A锁 ' % self.name) mutexB.acquire() print('%s拿到了B锁' % self.name) mutexB.release() print('%s 释放了 b锁' % self.name) mutexA.release() print('%s 释放了 a锁' % self.name) def f2(self): mutexB.acquire() time.sleep(2) print('%s 拿到了A锁 ' % self.name) mutexA.acquire() print('%s拿到了B锁' % self.name) mutexA.release() print('%s 释放了 b锁' % self.name) mutexB.release() print('%s 释放了 a锁' % self.name) if __name__ == '__main__': for i in range(5): t = Work() t.start()
信号量Semaphore 他是一种锁
Semaphore ()括号内的参数是几,就说明可以有几个可以用这段锁中的代码,并不是同事哦 谁先运行完,下一个就会进来。
信号量与进程池是有着同一种的用途,但是用法不同,很且差很多
from threading import Thread, Semaphore, currentThread import time,random sm = Semaphore(5) def work(): sm.acquire() print('