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多秒(因为线程只能并发)
#计算密集型
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密集型的任务时(同样是4个任务)
单核情况下和多核情况下都是开线程更节省资源
因为I/O型的任务需要不停的切换,所以即使是多个进程也需要在阻塞态等待,而开线程明显更节省资源。
#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、锁的更多相关文章
- 并发编程-多线程,GIL锁
本章内容: 1.什么是GIL 2.GIL带来的问题 3.为什么需要GIL 4.关于GIL的性能讨论 5.自定义的线程互斥锁与GIL的区别 6.线程池与进程池 7.同步异步,阻塞非阻塞 一.什么是GIL ...
- 多道技术 进程 线程 协程 GIL锁 同步异步 高并发的解决方案 生产者消费者模型
本文基本内容 多道技术 进程 线程 协程 并发 多线程 多进程 线程池 进程池 GIL锁 互斥锁 网络IO 同步 异步等 实现高并发的几种方式 协程:单线程实现并发 一 多道技术 产生背景 所有程序串 ...
- 53_并发编程-线程-GIL锁
一.GIL - 全局解释器锁 有了GIL的存在,同一时刻同一进程中只有一个线程被执行:由于线程不能使用cpu多核,可以开多个进程实现线程的并发,因为每个进程都会含有一个线程,每个进程都有自己的GI ...
- 操作系统/应用程序、操作中的“并发”、线程和进程,python中线程和进程(GIL锁),python线程编写+锁
并发编程前言: 1.网络应用 1)爬虫 直接应用并发编程: 2)网络框架 django flask tornado 源码-并发编程 3)socketserver 源码-并发编程 2.运维领域 1)自动 ...
- 并发,并行,线程,进程,GIL锁
1.并发和并行 并发: 同时做某些事,但是强调同一时段做多件事 如:同一路口,发生了车辆要同时通过路面的时间. 并行: 互不干扰的在同一时刻做多件事 如:同一时刻,同时有多辆车在多条车道上跑,即同时发 ...
- 并发编程: GIL锁、GIL与互斥锁区别、进程池与线程池的区别
一.GIL 二.关于GIL性能的讨论 三.计算密集测试 四.IO密集测试 五.GIL与互斥锁 六.TCP客户端 七.进程池 八.进程什么时候算是空闲 九.线程池 一.GIL GIL Global In ...
- python并发编程-多线程实现服务端并发-GIL全局解释器锁-验证python多线程是否有用-死锁-递归锁-信号量-Event事件-线程结合队列-03
目录 结合多线程实现服务端并发(不用socketserver模块) 服务端代码 客户端代码 CIL全局解释器锁****** 可能被问到的两个判断 与普通互斥锁的区别 验证python的多线程是否有用需 ...
- Python并发编程05 /死锁现象、递归锁、信号量、GIL锁、计算密集型/IO密集型效率验证、进程池/线程池
Python并发编程05 /死锁现象.递归锁.信号量.GIL锁.计算密集型/IO密集型效率验证.进程池/线程池 目录 Python并发编程05 /死锁现象.递归锁.信号量.GIL锁.计算密集型/IO密 ...
- [并发编程 - 多线程:信号量、死锁与递归锁、时间Event、定时器Timer、线程队列、GIL锁]
[并发编程 - 多线程:信号量.死锁与递归锁.时间Event.定时器Timer.线程队列.GIL锁] 信号量 信号量Semaphore:管理一个内置的计数器 每当调用acquire()时内置计数器-1 ...
- python并发编程之线程(创建线程,锁(死锁现象,递归锁),GIL锁)
什么是线程 进程:资源分配单位 线程:cpu执行单位(实体),每一个py文件中就是一个进程,一个进程中至少有一个线程 线程的两种创建方式: 一 from threading import Thread ...
随机推荐
- 目录服务不能与此服务器复制,因为距上一次与此服务器复制的时间已经超过了 tombstone 生存时间。
1.PDC数据正常 2.其他DC无法复制,报如下错误:目录服务不能与此服务器复制,因为距上一次与此服务器复制的时间已经超过了 tombstone 生存时间. 3.直接强制复制即可 repadmin / ...
- java 继承条件下的构造方法调用
运行 TestInherits.java示例,观察输出,注意总结父类与子类之间构造方法的调用关系修改Parent构造方法的代码,显式调用GrandParent的另一个构造函数,注意这句调用代码是否是第 ...
- 使用log4cxx
在java中有log4j日志模块,使用起来非常方便,在C++中也是有的,log4cxx就是log4j的c++移植版,机缘巧合之下今天想要使用一下这个日志模块,所以记录下自己从一开始下载安装到成功使用的 ...
- javaweb05 文件的上传一
2.使用fileupload组件完成文件的上传应用 1).需求: I. 上传 >在upload.jsp页面上使用jQuery实现"新增一个附件","删除附件&quo ...
- keras_yolo3阅读
源码地址 https://github.com/qqwweee/keras-yolo3 春节期间仔细看了看yolov3的kears源码,这个源码毕竟不是作者写的,有点寒酸,可能大道至简也是这么个理.我 ...
- JavaScript—封装animte动画函数
封装Animte 动画函数 虽然可能以后的开发中可能根本不需要自己写,Jquery 给我们封装好了,或者用CSS3的一些属性达到这样的效果可能更简单. 我比较喜欢底层的算法实现,万变不离其中,这个逻辑 ...
- html_js_jq_css
// ----- JQ $(function(){$(div').bind('mouseout mouseover', function () {// 移入和移出分别执行一次alert('bind 可 ...
- 熟练使用WebApi开发
在建立WebApi框架的时候,要想自己的业务需求是什么.例如PC端(前端),APP端都要使用的同一接口,就得考虑Webapi来提供接口支持了.最近公司刚好让我整合一下公司的接口项目(有WebServi ...
- 配对t检验
- Linux-proc文件系统介绍
1.操作系统级别的调试 (1).简单程序单步调试 (2).复杂程序printf打印信息调试 (3).框架体系日志记录信息调试 (4).内核调试的困境 2.proc虚拟文件系统的工作原理 (1).Lin ...