1. 程式人生 > 其它 >32.TCP服務端併發 GIL全域性鎖 死鎖 遞迴鎖 訊號量 event 執行緒佇列

32.TCP服務端併發 GIL全域性鎖 死鎖 遞迴鎖 訊號量 event 執行緒佇列

TCP

import socket

client = socket.socket()
client.connect(('127.0.0.1',8080))
while True:
    client.send(b'hello')
    data = client.recv(1024)
    print(data.decode('utf-8'))
client.py
""""""
"""
服務端
    1.要有固定的IP和PORT
    2.24小時不間斷提供服務
    3.能夠支援併發
"""
import socket
from threading import Thread

server 
= socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(5) def talk(conn): while True: try: data = conn.recv(1024) if len(data) == 0: break print(data.decode('utf-8')) conn.send(data.upper()) except ConnectionResetError as e:
print(e) break conn.close() while True: conn, addr = server.accept() # # 監聽 等待客戶端的連線 阻塞態 print(addr) t = Thread(target=talk, args=(conn,)) t.start()
server.py

 

""""""
"""
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple
native threads from executing Python bytecodes at once. This lock is necessary mainly
because CPython’s memory management is not thread-safe.
""" """ ps:python直譯器有很多種 最常見的就是Cpython直譯器 GIL本質也是一把互斥鎖:將併發變成序列犧牲效率保證資料的安全 用來阻止同一個程序下的多個執行緒的同時執行(同一個程序內多個執行緒無法實現並行但是可以實現併發) python的多執行緒沒法利用多核優勢 是不是就是沒有用了? GIL的存在是因為CPython直譯器的記憶體管理不是執行緒安全的 垃圾回收機制 1.引用計數 2.標記清除 3.分代回收 研究python的多執行緒是否有用需要分情況討論 四個任務 計算密集型的 10s 單核情況下 開執行緒更省資源 多核情況下 開程序 10s 開執行緒 40s 四個任務 IO密集型的 單核情況下 開執行緒更節省資源 多核情況下 開執行緒更節省資源 """ """計算密集型""" from multiprocessing import Process from threading import Thread import os,time def work(): res = 0 for i in range(1000): res*=i if __name__ == '__main__': l = [] s = [] print(os.cpu_count()) # 本機為 8核 start_time = time.time() for i in range(6): p = Process(target=work) t = Thread(target=work()) l.append(p) s.append(t) p.start() t.start() for p in l: p.join() for t in s: t.join() stop_time = time.time() print(stop_time-start_time) # 13.925952911376953 """IO密集型""" from multiprocessing import Process from threading import Thread import time,os def work(): time.sleep(2) if __name__ == '__main__': p_list = [] t_list = [] start = time.time() for i in range(4000): p = Process(target=work) t = Thread(target=work) p_list.append(p) t_list.append(t) p.start() t.start() for p in p_list: p.join() for t in t_list: t.join() stop = time.time() print('run time is %s' % (stop - start)) """ python的多執行緒到底有沒有用 需要看情況而定 並且肯定是有用的 多程序+多執行緒配合使用 """
1.GIL全域性直譯器鎖.py
from threading import Thread
import time

n = 100


def task():
    global n
    tmp = n
    # time.sleep(1)
    n = tmp -1

t_list = []
for i in range(100):
    t = Thread(target=task)
    t.start()
    t_list.append(t)

for t in t_list:
    t.join()

print(n)
2.GIL與普通互斥鎖.py
""""""
"""
Rlock 遞迴鎖
可以被第一個搶到鎖的人連續的acquire和release
每acquire一次鎖身上的計數加1
每release一次鎖身上的計數減1
只要鎖的計數不為0 其他人都不能搶

"""
from threading import Thread,Lock,current_thread,RLock

# mutexA = Lock()
# mutexB = Lock()
mutexA = mutexB = RLock() # # A B現在是同一把鎖


class MyThread(Thread):
    def run(self):# 建立執行緒自動觸發run方法 run方法內呼叫func1 func2相當於也是自動觸發
        self.func1()
        self.func2()
    def func1(self):
        mutexA.acquire()
        print(f'{self.name}搶到了A鎖') # # self.name等價於current_thread().name
        mutexB.acquire()
        print(f'{self.name}搶到了B鎖')
        mutexB.release()
        print(f'{self.name}釋放了B鎖')
        mutexA.release()
        print(f'{self.name}釋放了A鎖')

    def func2(self):
        mutexB.acquire()
        print(f'{self.name}搶到了B鎖')  # # self.name等價於current_thread().name
        mutexA.acquire()
        print(f'{self.name}搶到了A鎖')
        mutexA.release()
        print(f'{self.name}釋放了A鎖')
        mutexB.release()
        print(f'{self.name}釋放了B鎖')


for i in range(10):
    t = MyThread()
    t.start()


class Demo(object):
    pass

obj1 = Demo()
obj2 = Demo()
print(id(obj1),id(obj2))
# 2755671512512 2755671373248

"""
只要類加括號例項化物件
無論傳入的引數是否一樣生成的物件肯定不一樣
單例模式除外


自己千萬不要輕易的處理鎖的問題  

"""
3.死鎖.py
""""""
"""訊號量可能在不同的領域中 對應不同的知識點"""
"""
互斥鎖:一個廁所(一個坑位)
訊號量:公共廁所(多個坑位)
"""
from threading import Semaphore,Thread
import time
import random
sm = Semaphore(5) # 造成一個含有五個坑位的公共廁所

def task(name):
    sm.acquire()
    print(f'{name}佔了一個坑位')
    time.sleep(random.randint(1,3))
    sm.release()

for i in range(40):
    t = Thread(target=task,args=(i,))
    t.start()
4.訊號量.py
from threading import Event,Thread
import time

# 先生成一個event物件

e = Event()

def light():
    print('紅燈正亮著')
    time.sleep(3)
    e.set() # 發訊號
    print('綠燈亮了')

def car(name):
    print(f'{name} 正在等紅綠燈')
    e.wait() # 等待訊號
    print(f'{name} 加油門飆車')

t1 = Thread(target=light)
t1.start()

for i in range(10):
    t = Thread(target=car,args=(f'傘兵{i}',))
    t.start()
5.event事件.py
""""""
"""
同一個程序下的多個執行緒本來就是資料共享 為什麼還要用佇列

因為佇列是管道+鎖  使用佇列你就不需要自己手動操作鎖的問題 

因為鎖操作的不好極容易產生死鎖現象
"""
import queue

# q = queue.Queue()
# q.put('hahha')
# print(q.get())

"""先進後出,其他方法與Queue一致"""
# q = queue.LifoQueue()
# q.put(1)
# q.put(2)
# q.put(3)
# print(q.get())

"""#  3.PriorityQueue 傳入的引數要求是元組 '()'"""
"""數字越小,優先順序越高"""
q = queue.PriorityQueue()
# q.put((10,'haha'))
# q.put((100,'hehehe'))
# q.put((0,'xxxx'))
# q.put((-10,'yyyy'))
# print(q.get())
6.執行緒q.py