线程相关(二)

一. 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

研究python 的多线程是否有用需要分情况讨论
1.四个任务 计算密集型的
单核情况下
开线程比开进程更省资源
所以开线程好
多核情况下
开进程 要10S多
开线程 要40s多


2.四个任务 IO密集型 会不停的阻塞 不停的切
单核情况下
开线程更节省资源
多核情况下
开线程更节省资源

三.死锁

下面有个死锁的例子

复制代码
 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())
复制代码

 

posted @   s686编程传  阅读(114)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示