线程相关(二)

一. 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())
万般皆下品,唯有读书高!
原文地址:https://www.cnblogs.com/s686zhou/p/11357062.html