热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

进入python的世界_day35_网络编程——线程相关知识、GIL锁,互斥锁、event事件、池子、协程

上周五作业——多进程实现TCP服务端并发#服务端importsocketfrommultiprocessingimportProcessdefget_server():server

上周五作业——多进程实现TCP服务端并发

# 服务端
import socket
from multiprocessing import Process
def get_server():
server = socket.socket()
server.bind(('127.0.0.1', 9999))
server.listen(5)
return server # 把封装好属性的socket对象传出去给其他函数使用
def get_talk(sock):
while True:
data = sock.recv(1024)
print(data.decode('utf8'))
sock.send(data.upper())
if __name__ == '__main__':
server = get_server() # 拿到socket对象
while True:
sock, addr = server.accept() # 建立通道,拿到客户端地址
# 开设多进程去聊天
p = Process(target=get_talk, args=(sock,))
p.start()
_______________________________
# 客户端没差别,老样子写普通版本的

一、互斥锁——Lock、mutex

将并发、并行变为串行,牺牲了效率但是提升了数据安全

from multiprocessing import Process,Lock
造锁
mutex = Lock()
用锁
mutex.acquire() # 抢锁,得放在操作数据层
mutex.release() # 放锁

二、线程理论

​ 进程——资源单位

​ 线程——执行单位

​ 一个进程内部至少有一个线程!!!

​ 进程是开辟内存空间,线程是在进程上执行不占内存空间,所以创建进程的资源占用是比创建进程大的多的

from threading import Thread
import time
def a(name):
time.sleep(0.01) # 因为线程执行的飞快,加一个阻塞试试
print(f'{name} 正在运行')
time.sleep(3)
print(f'{name} 执行完毕')
if __name__ == '__main__':
t = Thread(target=a, args=('jack',))
t.start()
print('主线程执行了')

>>>
主线程执行了
jack 正在运行
jack 执行完毕

三、线程的诸多方法

1.join方法

​ 一样的,和进程

2.同一个进程下的多个线程数据共享

​ 因为不是多个复制内存空间,所以是共用的数据

3.线程名字

​ 类似进程ID一样的,current_thread

4.线程进程号

​ 同一个进程下的多个线程都是一个进程号

5.统计同一个进程下的线程数

​ activeCount

​ 注意如果没手动添加阻塞,用for循环生成多个线程,每循环生成一个执行完的线程就消失了

6.守护线程

​ 和守护进程一样

7.互斥锁

​ 也有Lock子模块,用法一样


四、GIL全局解释器锁——只在CPython有


1.介绍

​ 1.在CPython解释器中存在全局解释器锁简称GIL

​ python解释器有很多类型

​ CPython JPython PyPython (常用的是CPython解释器)

​ 2.GIL本质也是一把互斥锁 用来阻止同一个进程内多个线程同时执行(重要)

​ 3.GIL的存在是因为CPython解释器中内存管理不是线程安全的(垃圾回收机制)


2.如何绕过GIL

from threading import Thread
import time
num = 1
def a():
global num
c = num
time.sleep(0.5) # 其实这里和抢票差不多,因为是多线程,让线程都睡一会,又重新弄了一个变量名,强行避开了GIL锁
num = c + 1
t_list = []
for i in range(1, 100):
t = Thread(target=a)
t.start()
t_list.append(t)
for t in t_list: # 确保所有的进程全部运行完毕
t.join()
print(num)
>>>
2
# 如果不在a中新弄变量名,GIL锁会影响,得到结果为100

​ GIL 只能确保同进程内多线程数据不会被垃圾回收机制弄乱,不能确保程序里面的数据安全


验证python多线程 是否有用

需要分情况

1.cpu情况

​ 单个cpu

​ 多个cpu

2.代码情况

​ io密集型(代码有io操作)

​ 计算密集型(代码没有io)

3.单个cpu



  • io密集型

​ 1.多进程

​ 总耗时(单进程的耗时+io+申请空间+拷贝代码)

​ 2.多线程

​ 总耗时(单进程的耗时加+io)

​ !!!多线程有优势



  • 计算密集型

​ 1.多进程

​ 申请额外的空间 消耗更多的资源(总耗时+申请空间+拷贝代码+切换)

​ 2.多线程

​ 耗时资源相对较少 通过多道技术(总耗时+切换)

​ !!!多线程有优势

4.多个cpu



  • io密集型

​ 1.多进程

​ 总耗时(单个进程的耗时+io+申请空间+拷贝代码)

​ 2.多线程

​ 总耗时(单进程耗时+io)

​ !!!多线程有优势



  • 计算密集型

​ 1.多进程

​ 总耗时(单个进程的耗时)

​ 2.多线程

​ 总耗时(多个进程的综合)

​ !!!多进程完胜!



五、信号量

在python并发编程中信号量相当于多把互斥锁(打个比方公共厕所)

在其他的知识中意思达到某个条件自动触发其他操作

from threading import Thread, Lock, Semaphore
import time
import random
sp = Semaphore(5) # 一次性产生五把锁
class MyThread(Thread):
def run(self):
sp.acquire()
print(self.name)
time.sleep(random.randint(1, 3))
sp.release()
for i in range(20):
t = MyThread()
t.start()

# 相当于让20个人去挤厕所,厕所只有五个位置,哪个位置有人出来就可以新的人进去上

六、event事件——可以暂停线程或者进程

from threading import Thread, Event
import time
event = Event() # 造一个event对象
def light():
print('红路灯红灯亮着,等待绿灯>>>')
time.sleep(1)
print('3')
time.sleep(1)
print('2')
time.sleep(1)
print('1')
time.sleep(1)
print('绿灯亮了!游戏开始!')
event.set() # 让被等待的对象立马执行
def car(name):
print(f'{name} 正在起跑线等红绿灯')
event.wait() # 让根据这个函数产生的进程等着
print(f'游戏开始! {name}冲刺! ')
t = Thread(target=light)
t.start() # 这个函数产生的进程睡期间下面的代码执行,立马生成进程
for i in range(1, 10):
t = Thread(target=car, args=(f'棉花糖SR{i}',))
t.start()

>>>
红路灯红灯亮着,等待绿灯>>>
棉花糖SR1 正在起跑线等红绿灯
棉花糖SR2 正在起跑线等红绿灯
棉花糖SR3 正在起跑线等红绿灯
棉花糖SR4 正在起跑线等红绿灯
棉花糖SR5 正在起跑线等红绿灯
棉花糖SR6 正在起跑线等红绿灯
棉花糖SR7 正在起跑线等红绿灯
棉花糖SR8 正在起跑线等红绿灯
棉花糖SR9 正在起跑线等红绿灯
3
2
1
绿灯亮了!游戏开始!
游戏开始! 棉花糖SR4冲刺!
游戏开始! 棉花糖SR5冲刺!
游戏开始! 棉花糖SR2冲刺!
游戏开始! 棉花糖SR1冲刺!
游戏开始! 棉花糖SR8冲刺!
游戏开始! 棉花糖SR6冲刺!
游戏开始! 棉花糖SR3冲刺!
游戏开始! 棉花糖SR7冲刺!
游戏开始! 棉花糖SR9冲刺!

七、进程池、线程池

​ 能提前设置好最大进程、线程数量,可以有预防性的防止电脑因为进程或线程太多卡死

​ 当然,因为做出了限制,所以程序的执行效率是降低了

from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
import time
# 1产生固定数量的线程值
p = ProcessPoolExecutor(12)
# pool = ThreadPoolExecutor(10)
def test(name):
print(f'测试正在执行 测试员{name}>>>')
time.sleep(2)
print(f'测试执行完毕 测试员{name}>>>')
return '工作完成'
def func(a):
print('我来负责收结果')
print(a.result()) # 把返回值打印出来,得用result()
if __name__ == '__main__': # 进程别忘了main
for i in range(1, 24):
# 直接往池子里塞任务,池子按照设置好的数量分批创建进程
p.submit(test, 'jack').add_done_callback(func) # 通过调专门接收结果的函数来获取进程执行完的结果

八、协程——gevent第三方模块

​ 因为CPU才是干活的核心,而程序执行过程中如果碰到io操作,CPU会暂时离开,协程技术能欺骗CPU伪装代码中没有io操作,能让CPU一直陪同跟随,达到最大效率的目的。

​ 这个模块不需要去了解底层原理,这是别的大佬封装好的方法,会用就行

from gevent import monkey;
monkey.patch_all() # 固定语法,用于检测所有的IO操作(猴子补丁)
from gevent import spawn
import time
def a():
print('a 正在运行')
time.sleep(2)
print('a 执行结束')
def b():
print('b 正在运行')
time.sleep(3)
print('b 执行结束')
if __name__ == '__main__':
start_time = time.time()
a()
b()
print(time.time() - start_time)# >>> 5.056353569030762

————————————————————————————————————————————————————————
if __name__ == '__main__':
start_time = time.time()
s1 = spawn(a)
s2 = spawn(b)
s1.join()
s2.join()
print(time.time() - start_time) # >>>3.0264976024627686


九、单线程实现高并发

# 服务端
from gevent import monkey;
monkey.patch_all()
from gevent import spawn
import socket
def a(sock):
while True:
date = sock.recv(1024)
print(date.decode('utf8'))
sock.send(date.upper())
def s():
sever = socket.socket()
sever.bind(('127.0.0.1', 8088))
sever.listen(5)
while True:
sock, addr = sever.accept()
spawn(a, sock)
s1 = spawn(s)
s1.join()
————————————————————————————————————————————————————
# 客户端
import socket
c1 = socket.socket()
c1.connect(('127.0.0.1', 8088))
while True:
c1.send(b'hello world')
date = c1.recv(1024)
print(date.decode('utf8'))
# 记得去开pycharm中单一个Py文件的重复执行

↑↑↑↑↑↑↑↑





推荐阅读
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Python如何调用类里面的方法
    本文介绍了在Python中调用同一个类中的方法需要加上self参数,并且规范写法要求每个函数的第一个参数都为self。同时还介绍了如何调用另一个类中的方法。详细内容请阅读剩余部分。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Givenasinglylinkedlist,returnarandomnode'svaluefromthelinkedlist.Eachnodemusthavethe s ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
author-avatar
阵风阿斯顿
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有