并发编程(三)
作者:互联网
一. TCP server端通过线程实现并发
server端
1 from threading import Thread 2 import socket 3 4 sk = socket.socket() 5 sk.bind(('127.0.0.1',8080)) 6 sk.listen() 7 8 9 def talk(conn): 10 while True: 11 try: 12 data = conn.recv(1024) 13 print(data.decode('utf-8')) 14 conn.send(b'hello!') 15 except ConnectionRestError as e: 16 break 17 while True: 18 conn,addr = sk.accept() 19 print(addr) 20 t = Thread(target = talk,args = (conn,)) 21 t.start()
二.GIL全局解释器锁
是CPython中的解释器锁
通过一个例子了解GIL锁的存在
1 from threading import Thread 2 import time 3 n = 100 4 5 def task(): 6 global n 7 tmp = n 8 time.sleep(3) 9 n = tmp -1 10 11 t_list = [] 12 for i in range(100): 13 t = Thread(target = task) 14 t.start() 15 t_list.append(t) 16 17 for t in t_list: 18 t.join() 19 20 print(n)
在这种情况下 执行结果是99 因为这里有time.sleep(3) 这是IO操作,会阻塞,在此处线程会释放GIL锁,等待下一个线程来抢,因此直到最后一个线程抢到锁 才做最后的减1操作 因此最终的结果是99
如果将此处的time.sleep(3)注释掉之后 执行结果则是0
三.死锁
下面有个死锁的例子
1 from threading import Thread,Lock 2 import time 3 4 mutexA = Lock() 5 mutexB = Lock() 6 7 class MyThread(Thread): 8 def run(self): 9 self.func1() 10 self.func2() 11 12 def func1(self): 13 mutexA.acquire() 14 print('%s抢到了A锁'%self.name) #self.name 等价于 current_thread().name 15 mutexB.acquire() 16 print('%s抢到了B锁'%self.name) 17 mutexB.release() 18 print('%s释放了B锁'%self.name) 19 mutexA.release() 20 print('%s释放了A锁'%self.name) 21 22 def func2(self): 23 mutexB.acquire() 24 print('%s抢到了B锁' % self.name) 25 time.sleep(1) 26 mutexA.acquire() 27 print('%s抢到了A锁' % self.name) 28 mutexA.release() 29 print('%s释放了A锁' % self.name) 30 mutexB.release() 31 print('%s释放了B锁' % self.name) 32 33 for i in range(10): 34 t = MyThread() 35 t.start() 36 #结果: 37 ''' 38 Thread-1抢到了A锁 39 Thread-1抢到了B锁 40 Thread-1释放了B锁 41 Thread-1释放了A锁 42 Thread-1抢到了B锁 43 Thread-2抢到了A锁 44 死锁现象出现了 45 自己千万不要轻易处理锁的问题 46 '''
根据结果再推导一遍,首先线程一 抢到了A锁和B锁,然后释放B锁,现在的B锁没有人抢,因为A锁还在线程一身上没人能抢B锁,然后线程一将A锁释放,接着线程一执行func2方法抢到了B锁,而A锁在刚才释放的一瞬间被线程二抢走了,所以现在 线程一有B锁,线程二有A锁,之后线程一在func2方法中需要抢A锁,而线程二需要B锁,但是这两把锁再对方身上,所以这样就成了死锁现象。
四.递归锁
from threading import Thread,RLock #递归锁 可以连续acquire import time ''' RLock 可以被第一个抢到锁的人连续的acquire 和 release 每acquire一次 锁身上的计数加1 每release一次 锁身上的计数减1 只要锁的计数不为0 其他人不能抢 ''' mutexA = mutexB = RLock() #这是一把锁 同一把锁 class MyThread(Thread): def run(self): self.func1() self.func2() def func1(self): mutexA.acquire() print('%s抢到了A锁'%self.name) #self.name 等价于 current_thread().name mutexB.acquire() print('%s抢到了B锁'%self.name) mutexB.release() print('%s释放了B锁'%self.name) mutexA.release() print('%s释放了A锁'%self.name) def func2(self): mutexB.acquire() print('%s抢到了B锁' % self.name) time.sleep(1) mutexA.acquire() print('%s抢到了A锁' % self.name) mutexA.release() print('%s释放了A锁' % self.name) mutexB.release() print('%s释放了B锁' % self.name) for i in range(10): t = MyThread() t.start() #结果: ''' Thread-1抢到了A锁 Thread-1抢到了B锁 Thread-1释放了B锁 Thread-1释放了A锁 Thread-1抢到了B锁 Thread-1抢到了A锁 Thread-1释放了A锁 Thread-1释放了B锁 Thread-2抢到了A锁 Thread-2抢到了B锁 Thread-2释放了B锁 Thread-2释放了A锁 Thread-2抢到了B锁 Thread-2抢到了A锁 Thread-2释放了A锁 Thread-2释放了B锁 Thread-4抢到了A锁 Thread-4抢到了B锁 Thread-4释放了B锁 Thread-4释放了A锁 Thread-4抢到了B锁 Thread-4抢到了A锁 Thread-4释放了A锁 Thread-4释放了B锁 Thread-6抢到了A锁 Thread-6抢到了B锁 Thread-6释放了B锁 Thread-6释放了A锁 Thread-6抢到了B锁 Thread-6抢到了A锁 Thread-6释放了A锁 Thread-6释放了B锁 Thread-8抢到了A锁 Thread-8抢到了B锁 Thread-8释放了B锁 Thread-8释放了A锁 Thread-8抢到了B锁 Thread-8抢到了A锁 Thread-8释放了A锁 Thread-8释放了B锁 Thread-10抢到了A锁 Thread-10抢到了B锁 Thread-10释放了B锁 Thread-10释放了A锁 Thread-10抢到了B锁 Thread-10抢到了A锁 Thread-10释放了A锁 Thread-10释放了B锁 Thread-5抢到了A锁 Thread-5抢到了B锁 Thread-5释放了B锁 Thread-5释放了A锁 Thread-5抢到了B锁 Thread-5抢到了A锁 Thread-5释放了A锁 Thread-5释放了B锁 Thread-9抢到了A锁 Thread-9抢到了B锁 Thread-9释放了B锁 Thread-9释放了A锁 Thread-9抢到了B锁 Thread-9抢到了A锁 Thread-9释放了A锁 Thread-9释放了B锁 Thread-7抢到了A锁 Thread-7抢到了B锁 Thread-7释放了B锁 Thread-7释放了A锁 Thread-7抢到了B锁 Thread-7抢到了A锁 Thread-7释放了A锁 Thread-7释放了B锁 Thread-3抢到了A锁 Thread-3抢到了B锁 Thread-3释放了B锁 Thread-3释放了A锁 Thread-3抢到了B锁 Thread-3抢到了A锁 Thread-3释放了A锁 Thread-3释放了B锁 '''
五.信号量
信号量可能再不同的领域中,对应不同的知识点
这里将信号量与互斥锁做个对比
互斥锁 :一个坑位的厕所
信号量:多个坑位的厕所
例子
1 rom threading import Semaphore,Thread 2 import time 3 sm = Semaphore(5) #造了一个含有5个坑位的公共厕所 4 5 def task(name): 6 sm.acquire() 7 print('%s占了一个坑位'%name) 8 time.sleep(1) 9 sm.release() 10 11 12 for i in range(40): 13 t = Thread(target=task,args=(i,)) 14 t.start()
六.event事件
from threading import Event,Thread import time #先生成一个event对象 e = Event() def light(): print('红灯亮..') time.sleep(3) e.set() #发信号 print('绿灯亮..') def car(name): print('%s正在等红灯..'%name) e.wait() #等待信号 print('%s加油门飙车'%name) t = Thread(target=light) t.start() for i in range(3): t = Thread(target=car,args=('伞兵%s'%i,)) t.start()4 #执行结果 红灯亮.. 伞兵0正在等红灯.. 伞兵1正在等红灯.. 伞兵2正在等红灯.. 绿灯亮.. 伞兵0加油门飙车 伞兵1加油门飙车 伞兵2加油门飙车
七.线程q
同一个进程下的多个线程本来就是数据共享的
为什么还用队列呢?
因为队列是 管道+锁
使用队列就不需要自己手动操作锁的问题
因为锁操作的不好极容易产生死锁现象
三个常见的:
1.
1 import queue 2 q = queue.Queue() 3 q.put('haha') 4 print(q.get())
2.
import queue q = queue.LifoQueue() #后进先出 q.put(1) q.put(2) q.put(3) print(q.get())
3.
import queue q = queue.PriorityQueue() #数字越小 优先级越高 q.put((10,'haha')) q.put((-10,'h3h3')) q.put((0,'xxx')) print(q.get()) print(q.get())
标签:释放,name,Thread,self,编程,并发,抢到,print 来源: https://www.cnblogs.com/s686zhou/p/11357062.html