TCP并发、GIL全局锁、多线程讨论
TCP实现并发
#client客户端
import socket client = socket.socket()
client.connect(('127.0.0.1',8080)) while True:
msg = input('>>>:').strip()
if len(msg) == 0:continue
client.send(msg.encode('utf-8'))
data = client.recv(1024)
print(data.decode('utf-8')) #server服务端
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() #通过创建线程的方式,让线程来“接待”连入的客户端从而达到并发的效果
GIL全局解释器锁
GIL本质就是一把互斥锁:将并发变成串行牺牲效率保证数据的安全。
用来阻止同一个进程下的多个线程的同时执行(同一进程内多个线程无法实现并行但可以实现并发)
CIL的存在是因为Cpython解释器的内存管理,而不是线程安全。
#用代码来验证
from threading import Thread
import time n = 100 def task():
global n
tmp = n
#time.sleep(1) # 如果让程序睡眠一秒(即出现I/O操作,会自动释放锁,导致最后的到的结果是99,这是因为在你释放锁了之后别的子线程也可以抢锁拿到这个数据,然后再进行操作,如果不让程序睡眠(不让程序出现I/O操作的话),那么就和普通的互斥锁一样,谁抢到谁来运行,最后结果是0)
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)
python多线程是否有用的讨论
因为python的多线程并不能利用多核优势,那么python的多线程是否还有用?
这个需要分情况讨论:
在计算密集型的任务时(比如有4个任务,每个任务是10秒)
单核情况下:
开线程更省资源(因为单核情况下都是并发,开线程的资源明显比开进程的资源少)
多核情况下:
开进程可能是10秒多(多核的情况下,开进程可以达到一个并行的效果,所以4个一起执行的时间相当于每一个的时间),而开线程可能需要40多秒(因为线程只能并发)
在I/O密集型的任务时(同样是4个任务)
单核情况下和多核情况下都是开线程更节省资源
因为I/O型的任务需要不停的切换,所以即使是多个进程也需要在阻塞态等待,而开线程明显更节省资源。
#计算密集型
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=[]
print(os.cpu_count()) # 本机为6核
start=time.time()
for i in range(6):
# p=Process(target=work) #耗时 4.732933044433594
p=Thread(target=work) #耗时 22.83087730407715
l.append(p)
p.start()
for p in l:
p.join()
stop=time.time()
print('run time is %s' %(stop-start))
#多核的情况下,计算密集型开进程比开线程快
#I/O密集型
from multiprocessing import Process
from threading import Thread
import threading
import os,time
def work():
time.sleep(2) if __name__ == '__main__':
l=[]
print(os.cpu_count()) #本机为6核
start=time.time()
for i in range(4000):
p=Process(target=work) #耗时9.001083612442017s多,大部分时间耗费在创建进程上
# p=Thread(target=work) #耗时2.051966667175293s多
l.append(p)
p.start()
for p in l:
p.join()
stop=time.time()
print('run time is %s' %(stop-start))
#I/O密集型的情况下开线程比开进程快
死锁与递归锁
#死锁
from threading import Thread,Lock,current_thread
import time mutexA = Lock()
mutexB = Lock() 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()
#当出现Thread-1抢到了锁B,Thread-2抢到了锁A的时候,程序卡主,也就是进入了死锁状态,这是因为Thread-1在执行到func2中的抢锁B时,锁A被Thread-2抢到了,这时Thread-1的下一步是抢锁A,但被Thread-2已经占住了,而Thread-2下一步要抢的锁B此时被Thread-1占住,谁都进行不了下一步,所以卡住,于是出现了死锁现象。
#递归锁
from threading import Thread,RLock,current_thread
import time mutexA = mutexB = RLock() class MyThread(Thread):
def run(self):
self.func1()
self.func2() def func1(self):
mutexA.acquire()
print('%s抢到了锁A'%self.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() #设置event的状态为True,唤醒被阻塞的线程# 发信号
print('绿灯亮了') def car(name):
print('%s正在等红灯'%name)
e.wait() # 设置event的状态为False,阻塞线程# 等待信号
print('%s加油门飙车了'%name) t = Thread(target=light)
t.start() for i in range(10):
t = Thread(target=car,args=('伞兵%s'%i,))
t.start()
#event的作用是,生产一个Event对象,在线程执行到某个阶段的时候我们可以设置一个Event对象,通过改变event对象的状态来阻塞或者唤醒线程的执行。
线程q
同一个进程下的多个线程本来就是数据共享,为什么还要用队列,因为队列是管道+锁,使用队列就不需要你来自己手动操作锁的问题,而且锁操作的不好容易产生死锁现象。
import queue
q = queue.Queue() # 先进先出
q.put('hahaha')
q.put('hihihi')
print(q.get()) q = queue.LifoQueue() #后进先出
q.put(1)
q.put(2)
q.put(3)
print(q.get()) q = queue.PriorityQueue()
#put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小(可以是负的)优先级越高
q.put((10,'haha'))
q.put((100,'hehehe'))
q.put((0,'xxx'))
q.put((-10,'yyy'))
print(q.get())
TCP并发、GIL全局锁、多线程讨论的更多相关文章
- python GIL 全局锁,多核cpu下的多线程性能究竟如何?
python GIL 全局锁,多核cpu下的多线程性能究竟如何?GIL全称Global Interpreter Lock GIL是什么? 首先需要明确的一点是GIL并不是Python的特性,它是在实现 ...
- [ Python - 11 ] 多线程及GIL全局锁
1. GIL是什么? 首先需要明确的一点是GIL并不是python的特性, 它是在实现python解析器(Cpython)时所引入的一个概念. 而Cpython是大部分环境下默认的python执行环境 ...
- 并发编程-线程-死锁现象-GIL全局锁-线程池
一堆锁 死锁现象 (重点) 死锁指的是某个资源被占用后,一直得不到释放,导致其他需要这个资源的线程进入阻塞状态. 产生死锁的情况 对同一把互斥锁加了多次 一个共享资源,要访问必须同时具备多把锁,但是这 ...
- 8.14 day32 TCP服务端并发 GIL解释器锁 python多线程是否有用 死锁与递归锁 信号量event事件线程q
TCP服务端支持并发 解决方式:开多线程 服务端 基础版 import socket """ 服务端 1.要有固定的IP和PORT 2.24小时不间断提供服务 3.能够支 ...
- python并发编程-多线程实现服务端并发-GIL全局解释器锁-验证python多线程是否有用-死锁-递归锁-信号量-Event事件-线程结合队列-03
目录 结合多线程实现服务端并发(不用socketserver模块) 服务端代码 客户端代码 CIL全局解释器锁****** 可能被问到的两个判断 与普通互斥锁的区别 验证python的多线程是否有用需 ...
- Python-多线程之消费者模式和GIL全局锁
一.生产者和消费者模式 什么是生产者消费者模式 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯, 所以生产者生产完数据之后不 ...
- GIL全局锁测试
基础知识:https://www.cnblogs.com/SuKiWX/p/8804974.html 测试环境 python3.7默认解释器(cpython) cpu为四核 测试代码 #! /usr/ ...
- TCP并发、GIL、锁
TCP实现并发 #client客户端 import socket client = socket.socket() client.connect(('127.0.0.1',8080)) while T ...
- [py]GIL(全局解释器锁):多线程模式
在多线程 时同一时刻只允许一个线程来访问CPU,直到解释器遇到I/O操作或者操作次数达到一定数目时才会释放GIL 参考 Python虽然不能利用多线程实现多核任务,但可以通过多进程实现多核任务.多个P ...
随机推荐
- c++语法(1)
#include<iostream> #include<windows.h> using namespace std; class Parents { public: ; // ...
- 13)PHP,文件加载(include和require)
有四种文件加载的语法形式(注意,不是函数): include, include_once, require, require_once; 他们的本质是一样的,都是用于加载/引入/包含/载入一个外部 ...
- IntelliJ IDEA 2019.2.2在16GB内存下的性能调优
开发工具 IntelliJ IDEA 2019.2.2 x64 idea64.exe.vmoptions -m -m -XX:ReservedCodeCacheSize=m -XX:+UseConcM ...
- 计算文本长度-boundingRectWithSize
- (void)viewDidLoad { [super viewDidLoad]; //新建lable控件 UILabel *lable=[[UILabel alloc]init]; labl ...
- [JSOI2019]神经网络(树形DP+容斥+生成函数)
首先可以把题目转化一下:把树拆成若干条链,每条链的颜色为其所在的树的颜色,然后排放所有的链成环,求使得相邻位置颜色不同的排列方案数. 然后本题分为两个部分:将一棵树分为1~n条不相交的链的方案数:将这 ...
- [HNOI2019]序列(单调栈+二分)
通过打表证明发现答案就是把序列划分成若干段,每段的b都是这一段a的平均数.50分做法比较显然,就是单调栈维护,每次将新元素当成一个区间插入末尾,若b值不满足单调不降,则将这个区间与单调栈前一个区间合并 ...
- 【线段树】Interval GCD
题目描述 给定一个长度为N的数列A,以及M条指令 (N≤5*10^5, M<=10^5),每条指令可能是以下两种之一: "C l r d",表示把 A[l],A[l+1],- ...
- Spring Boot使用Liquibase最佳实践
Liquibase问题 随着项目的发展,一个项目中的代码量会非常庞大,同时数据库表也会错综复杂.如果一个项目使用了Liquibase对数据库结构进行管理,越来越多的问题会浮现出来. ChangeSet ...
- 39)PHP,选取数据库中的两列
首先是我的文件关系: 我的b.php是主php文件,BBB.php是配置文件,login.html是显示文件, b.php文件代码: <?php /** * Created by PhpStor ...
- mac vmware fusion10 nat 模式网络配置
mac vmware fusion10 nat 模式网络配置 1.虚拟机选择 nat 模式 虚拟机-->网络适配器-->网络适配器设置-->连接网络适配器(对勾)-->与我的 ...