1、死锁
定义; 类似两个人分别被囚禁在两间房子里,A手上拿着的是B囚禁房间的钥匙,而B拿着A的钥匙,两个人都没法出去,没法给对方开锁,进而造成死锁现象。
具体例子代码如下:
# -*-coding:utf-8 -*- from threading import Thread,Lock,RLock import time muxeA=Lock() muxeB=Lock() class MyThread(Thread): def run(self): self.func1() self.func2() def func1(self): muxeA.acquire() print('%s抢到A锁了'%self.name) muxeB.acquire() print('%s抢到B锁了' % self.name) muxeB.release() muxeA.release() def func2(self): muxeB.acquire() print('%s抢到B锁了' % self.name) time.sleep(2) muxeA.acquire() print('%s抢到A锁了' % self.name) muxeA.release() muxeB.release() if __name__ == '__main__': for i in range(10): t=MyThread() t.start()
分析:
当执行func1的时候,第一个人(a)先抢到锁A,这时候,
其他人只能继续等待抢锁A,没有人跟a抢锁B,所以a也抢到锁B,
拿到锁B后,a就把锁B先释放掉,再释放锁A,
继续执行func2,a也顺利抢到锁B,这时候,睡眠2s,
而锁A已经被第二个人抢到了,这时候,第二个人只拿到锁A,没有拿到锁B,
所以没有释放锁A,而a一直在等待抢锁A,没有释放锁B,
所以这时候就造成等待死循环的情况。
执行结果如下:
递归锁使用:from reading import RLock
递归锁的特点:
1、可以被连续的acquire和release
2、但是,只能第一个抢到这把锁执行上述操作
3、它内部有一个计数器,每acquire一次计数加一,每realse一次计数减一
4、只要计数不为0,那么其他人都无法抢到该锁
具体例子代码如下:
# -*-coding:utf-8 -*- from threading import Thread,RLock import time muxeA=muxeB=RLock() class MyThread(Thread): def run(self): self.func1() self.func2() def func1(self): muxeA.acquire() print('%s抢到A锁了'%self.name) muxeB.acquire() print('%s抢到B锁了' % self.name) muxeB.release() muxeA.release() def func2(self): muxeB.acquire() print('%s抢到B锁了' % self.name) time.sleep(2) muxeA.acquire() print('%s抢到A锁了' % self.name) muxeA.release() muxeB.release() if __name__ == '__main__': for i in range(10): t=MyThread() t.start()
执行结果如下(没有出现死锁现象):
3、信号量:
定义:就相当于多个互斥锁:
具体例子如下:
from threading import Thread,Semaphore import time,random s=Semaphore(5) def task(name): s.acquire() print('%s号停车位正在停车'%name) time.sleep(random.randint(1,5)) s.release() if __name__ == '__main__': for i in range(10): t=Thread(target=task,args=(i,)) t.start()
比如:一些线程需要等待另一些线程完成才可以操作, 就类似发送信号一样。
from threading import Thread,Event import time,random event=Event() def light(): print("红灯") time.sleep(3) print('绿灯') event.set() #发送信号 def car(name): print('%s车正在等红灯'%name) event.wait() #等待对方发信号过来 print('%s车过绿灯'%name) if __name__ == '__main__': t=Thread(target=light) t.start() for i in range(10): t1=Thread(target=car,args=(i,)) t1.start()
池的概念:就是保证计算硬件的安全前提下,最大限度的利用计算机。
它降低运行效率,但是,保证了计算机硬件的安全。
注意: 池里面原有的线程或进程是不会重复出现创建和销毁的过程。
#线程池的创建: pool=ThreadPoolExecutor() #括号内为线程池中进程的个数,你可以自己设置,默认是5个,最大不会超过32个 ThreadPoolExecutor类中的参数max_workers就是池中线程数:初始设置代码如下: max_workers = min(32, (os.cpu_count() or 1) + 4) #进程池的创建: pool=ProcessPoolExecutor() #它的参数如下:os.cpu_count()表示电脑的CPU核数 self._max_workers = os.cpu_count() or 1 总结:关键代码如下: from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor pool=ProcessPoolExecutor() pool=ThreadPoolExecutor(5) res=pool.submit(task,i).add_done_callback(call_back)
进程/线程池的例子如下:
# -*-coding:utf-8 -*- from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor import time,os # pool=ThreadPoolExecutor(5) pool=ProcessPoolExecutor() def call_back(n): print(">>:",n.result()) def task(n): print(n,os.getpid()) time.sleep(2) return n*n if __name__ == '__main__': # list_pool=[] for i in range(10): res=pool.submit(task,i).add_done_callback(call_back)
实质:就是一个思想,它是由程序员自己在代码层面上检测IO操作,一旦遇到IO操作就会在代码级别上完成切换
注意:IO操作下的切换才是提高效率的,非IO操作下的切换会降低效率。
gevent模块的使用需要打猴子补丁,不然不会检测到像time.sIeep()等O操作
#猴子补丁 from gevent import monkey monkey.patch_all()
具体例子如下:
# -*-coding:utf-8 -*- #猴子补丁 from gevent import monkey monkey.patch_all() from gevent import spawn import time def ha(): print('hahaha') time.sleep(2) print('hahaha') def xixi(): print('xixi') time.sleep(3) print('xixi') if __name__ == '__main__': start_time=time.time() g1=spawn(ha) g2=spawn(xixi) g1.join() g2.join() print(time.time()-start_time)
服务端例子如下:
1 # -*-coding:utf-8 -*- 2 #猴子补丁 3 from gevent import monkey;monkey.patch_all() 4 5 from gevent import spawn 6 import socket 7 8 def new_server(ip,addr): 9 server=socket.socket() 10 server.bind((ip,addr)) 11 server.listen(5) 12 while True: 13 conn,addr=server.accept() 14 spawn(connect,conn) 15 16 def connect(conn): 17 while True: 18 try: 19 data=conn.recv(1024) 20 print(data.decode()) 21 if len(data)==0:break 22 conn.send(data.upper()) 23 except Exception as e: 24 print(e) 25 break 26 if __name__ == '__main__': 27 g1=spawn(new_server,'localhost',8080) 28 g1.join()
客户端代码如下:
1 # -*-coding:utf-8 -*- 2 import socket 3 from threading import Thread,current_thread 4 5 def new_client(): 6 c=socket.socket() 7 c.connect(('localhost',8080)) 8 while True: 9 data=('你好,我是%s'%current_thread().name) 10 c.send(data.encode()) 11 data1=c.recv(1024) 12 print(data) 13 14 if __name__ == '__main__': 15 for i in range(200): 16 t=Thread(target=new_client) 17 t.start()