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 ...
随机推荐
- python paramiko登陆设备
一,单线程 - shell交互 def chan_recv(chan): data = chan.recv(1024) # 收1024数据 sys.stdout.write(data.decode() ...
- python-day8爬虫基础之数据存储
数据存储,在爬虫中也是十分的重要,因为我们要把我们想要的数据保存到本地,其中最简单直接的就是保存为文件文本,比如:TXT.JSON.CSV等等,除此之外,我们还可以将其保存到数据库中,常见的数据库类型 ...
- ansible puppet saltstack三款自动化运维工具的对比
一.基础介绍 ansible基础介绍可参考:http://www.linuxidc.com/Linux/2017-12/149671.htm puppet基础介绍可参考:http://www.linu ...
- 分享一套好看的PyCharm Color Shceme 配色方案
配色方案图1 点击可查看大图 (color shceme 配色文件下载链接已经放在文末) 配色方案图2 配色方案图3 picture1 picture2 整体效果 下载链接 https://files ...
- StartDT AI Lab | 智能运筹助力企业提升决策效率、优化决策质量
在人工智能和大数据时代,越来越多的云上数据和越来越智能的模型开始辅助人们做出各种最优决策,从运营效率.成本节约.最优配置等方方面面,实现降本增效,进一步提升商业效率.京东.美团.滴滴.顺丰等众多知名厂 ...
- CaptchaCodeManager
package org.linlinjava.litemall.wx.service; import org.linlinjava.litemall.wx.dto.CaptchaItem; impor ...
- webservice SOA
------------------认证问题
- Opencv笔记(五)——把鼠标当画笔
学习目标: 学习使用 OpenCV 处理鼠标事件 学会使用函数cv2.setMouseCallback() 简单演示: 首先我们来创建一个鼠标事件回调函数,但鼠标事件发生是他就会被执 ...
- Windows系统清理
@echo off del/f/s/q %systemdrive%\*.tmp del/f/s/q %systemdrive%\*._mp del/f/s/q %systemdrive%\*.log ...
- 903C. Boxes Packing#俄罗斯套娃问题(map使用)
题目出处:http://codeforces.com/problemset/problem/903/C 题目大意:求这组数据中数据出现的最大重复次数 #include<iostream> ...