TCP通信
服务端: 1.要有固定的IP和PORT, 2. 24小时不间断提供服务, 3.能够支持并发
客户端 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')) 服务端 import socket from threading import Thread server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen(5) def task(conn): while True: try: data = conn.recv(1024) if 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() t = Thread(target=task,args=(conn,)) t.start()
python解释器有很多种 最常见的就是Cpython解释器, GIL本质也是一把互斥锁:将并发变成串行牺牲效率保证数据的安全, 用来阻止同一个进程下的多个线程的同时执行(同一个进程内多个线程无法实现并行但是可以实现并发),GIL的存在是因为CPython解释器的内存管理不是线程安全的
垃圾回收机制: 1.引用计数 2.标记清除 3.分代回收
四个任务 计算密集型的 10s
单核情况下 开线程更省资源
多核情况下 开进程 10s 开线程 40s
四个任务 IO密集型的
单核情况下 开线程更节省资源
多核情况下 开线程更节省资源
计算密集型 from multiprocessing import Process from threading import Thread import os,time def work(): res = 0 for i in range(100000000): res *= i if __name__ == '__main__': l = [] print(os.cpu_count()) start = time.time() for i in range(4): # p = Thread(target=work) # 20.15457773208618 p = Process(target=work) # 10.021640539169312 l.append(p) p.start() for p in l: p.join() stop = time.time() print('run time is %s'%(stop-start)) IO密集型 from multiprocessing import Process from threading import Thread import threading import time,os def work(): time.sleep(1) if __name__ == '__main__': l = [] print(os.cpu_count()) start = time.time() for i in range(400): p = Process(target=work) # 10.692718029022217 # p=Thread(target=work) # 1.040785312652588 l.append(p) p.start() for p in l: p.join() stop = time.time() print(stop-start)
GIL与普通的互斥锁
from threading import Thread import time n = 100 def test(): global n tmp = n time.sleep(1) n = tmp - 1 t_list = [] for i in range(100): t = Thread(target=test) t_list.append(t) t.start() for t in t_list: t.join() print(n)
死锁
from threading import Thread,Lock,current_thread,RLock import time """ Rlock可以被第一个抢到锁的人连续的acquire和release 每acquire一次锁身上的计数加1 每release一次锁身上的计数减1 只要锁的计数不为0 其他人都不能抢 """ # 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('%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()
信号量
""" 互斥锁:一个厕所(一个坑位) 信号量:公共厕所(多个坑位) """ from threading import Semaphore,Thread import time import random sm = Semaphore(5) # 造了一个含有五个的坑位的公共厕所 def task(name): sm.acquire() print('%s占了一个坑位'%name) time.sleep(random.randint(1,3)) sm.release() for i in range(40): t = Thread(target=task,args=(i,)) 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(10): t = Thread(target=car,args=('伞兵%s'%i,)) t.start()
线程q
import queue """ 同一个进程下的多个线程本来就是数据共享 为什么还要用队列 因为队列是管道+锁 使用队列你就不需要自己手动操作锁的问题 因为锁操作的不好极容易产生死锁现象 """ # q = queue.Queue() # q.put('hahha') # print(q.get()) # q = queue.LifoQueue() # q.put(1) # q.put(2) # q.put(3) # print(q.get()) # q = queue.PriorityQueue() # # 数字越小 优先级越高 # q.put((10,'haha')) # q.put((100,'hehehe')) # q.put((0,'xxxx')) # q.put((-10,'yyyy')) # print(q.get())