并发编程: GIL锁、GIL与互斥锁区别、进程池与线程池的区别
本文目录:
一、GIL
什么叫GIL
全局解释器锁(GIL Global Interpreter Lock),锁就是线程里面那个锁,锁是为了避免资源竞争造成数据的错乱,python程序的执行过程,1.启动解释器进程 python.exe,
2.解析你的py文件并执行它,每个py程序中都必须有解释器参与解释器其实就是一堆代码,相当于多个线程要调用同一个解释器代码,共享以为竞争 ,竞争就要出事,所以给解释器加锁。
python 中内存管理依赖于 GC(一段用于回收内存的代码) 也需要一个线程
除了你自己开的线程 系统还有一些内置线程 就算你的代码不会去竞争解释器 内置线程也可能会竞争
所以必须加上锁 当一个线程遇到了IO 同时解释器也会自动解锁 去执行其他线程 CPU会切换到其他程序 x = obj +1
a = obj +1 2 x = None -1
a = None -1 0
二、关于GIL性能的讨论
"""
解释器加锁以后
将导致所有线程只能并发 不能达到真正的并行 意味着同一时间只有一个CPU在处理你的线程
给你的感觉是效率低 代码执行有两种状态
阻塞 i/o 失去CPU的执行权 (CPU等待IO完成)
非阻塞 代码正常执行 比如循环一千万次 中途CPU可能切换 很快会回来 (CPU在计算) 假如有32核CPU 要处理一个下载任务 网络速度慢 100k/s 文件大小为1024kb
如果你的代码中IO操作非常多 cpu性能不能直接决定你的任务处理速度 案例:
目前有三个任务 每个任务处理需一秒 获取元数据需要一小时
3个CPU 需要 一小时1秒
1个cpu 需要 一小时3秒 在IO密集的程序中 CPU性能无法直接决定程序的执行速度 python就应该干这种活儿
在计算密集的程序中 CPU性能可以直接决定程序的执行速度 """
三、计算密集测试
from threading import Thread
from multiprocessing import Process
import time # 计算密集任务 def task1():
sum = 1
for i in range(10000000):
sum *= i def task2():
sum = 1
for i in range(10000000):
sum *= i def task3():
sum = 1
for i in range(10000000):
sum *= i def task4():
sum = 1
for i in range(10000000):
sum *= i def task5():
sum = 1
for i in range(10000000):
sum *= i def task6():
sum = 1
for i in range(10000000):
sum *= i if __name__ == '__main__': # 开始时间
st_time = time.time()
# 多线程情况下
# t1 = Thread(target=task1)
# t2 = Thread(target=task2)
# t3 = Thread(target=task3)
# t4 = Thread(target=task4)
# t5 = Thread(target=task5)
# t6 = Thread(target=task6) t1 = Process(target=task1)
t2 = Process(target=task2)
t3 = Process(target=task3)
t4 = Process(target=task4)
t5 = Process(target=task5)
t6 = Process(target=task6) t1.start()
t2.start()
t3.start()
t4.start()
t5.start()
t6.start()
#
# t1.join()
# t2.join()
# t3.join()
# t4.join()
# t5.join()
# t6.join() print(time.time() - st_time)
四、IO密集测试
from threading import Thread
from multiprocessing import Process
import time # 计算密集任务
def task1():
time.sleep(3) def task2():
time.sleep(3) def task3():
time.sleep(3) def task4():
time.sleep(3) def task5():
time.sleep(3) def task6():
time.sleep(3) if __name__ == '__main__': # 开始时间
st_time = time.time()
# 多线程情况下
# t1 = Thread(target=task1)
# t2 = Thread(target=task2)
# t3 = Thread(target=task3)
# t4 = Thread(target=task4)
# t5 = Thread(target=task5)
# t6 = Thread(target=task6) t1 = Process(target=task1)
t2 = Process(target=task2)
t3 = Process(target=task3)
t4 = Process(target=task4)
t5 = Process(target=task5)
t6 = Process(target=task6) t1.start()
t2.start()
t3.start()
t4.start()
t5.start()
t6.start() # t1.join()
# t2.join()
# t3.join()
# t4.join()
# t5.join()
# t6.join() print(time.time() - st_time)
五、GIL与互斥锁
from threading import Thread,Lock
import time mutex = Lock()
num = 1
def task():
global num
# print(num)
mutex.acquire()
temp = num
print(temp)
time.sleep(1) # 当你们线程中出现io时 GIL锁就解开
num = temp + 1
mutex.release() # 线程任务结束时GIL锁解开 t1 = Thread(target=task,) t2 = Thread(target=task,)
t1.start()
t2.start()
t1.join()
t2.join()
print(num) #
# GIL 和 自定义互斥锁的区别
# 全局锁不能保证自己开启的线程安全 但是保证解释器中的数据的安全的
# GIL 在线程调用解释器时 自动加锁 在IO阻塞时或线程代码执行完毕时 自动解锁
#
六、进程池
"""
进程池
就是一个装进程的容器
为什么出现
当进程很多的时候方便管理进程
什么时候用?
当并发量特别大的时候 列入双十一
很多时候进程是空闲的 就让他进入进程池 让有任务处理时才从进程池取出来使用
进程池使用
ProcessPoolExecutor类
创建时指定最大进程数 自动创建进程
调用submit函数将任务提交到进程池中
创建进程是在调用submit后发生的 总结一下:
进程池可以自动创建进程
进程限制最大进程数
自动选择一个空闲的进程帮你处理任务
遗留问题 进程什么时候算是空闲 """
import socket
from multiprocessing import Process from concurrent.futures import ProcessPoolExecutor # 收发数据
def task(c, addr):
while True:
try:
data = c.recv(1024)
print(data.decode("utf-8"))
if not data:
c.close()
break
c.send(data.upper())
except Exception:
print("连接断开")
c.close()
break if __name__ == '__main__': server = socket.socket() server.bind(("127.0.0.1",65535)) server.listen(5) # 创建一个进程池 默认为CPU个数
pool = ProcessPoolExecutor() while True:
c,addr = server.accept()
# p = Process(target=task,args=(c,addr))
# p.start()
pool.submit(task,c,addr)
七、进程什么时候算是空闲
from concurrent.futures import ProcessPoolExecutor import os,time,random def task():
time.sleep(random.randint(1,2))
print(os.getpid()) def run():
pool = ProcessPoolExecutor(2)
for i in range(30):
pool.submit(task) if __name__ == '__main__':
run()
八、线程池
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
from threading import current_thread import os,time,random def task():
time.sleep(random.randint(1,2))
print(current_thread()) def run():
# 默认为cpu核心数 * 5
pool = ThreadPoolExecutor(3)
for i in range(30):
pool.submit(task) if __name__ == '__main__':
run()
并发编程: GIL锁、GIL与互斥锁区别、进程池与线程池的区别的更多相关文章
- python并发编程之多进程(二):互斥锁(同步锁)&进程其他属性&进程间通信(queue)&生产者消费者模型
一,互斥锁,同步锁 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的, 竞争带来的结果就是错乱,如何控制,就是加锁处理 part1:多个进程共享同一打印终 ...
- Java并发编程实战(3)- 互斥锁
我们在这篇文章中主要讨论如何使用互斥锁来解决并发编程中的原子性问题. 目录 概述 互斥锁模型 互斥锁简易模型 互斥锁改进模型 Java世界中的互斥锁 synchronized中的锁和锁对象 synch ...
- java并发编程实战《三》互斥锁(上)
互斥锁(上):解决原子性问题 原子性问题的源头是线程切换,操作系统做线程切换是依赖 CPU 中断的,所以禁止 CPU 发生中断就能够禁止线程切换. 在早期单核 CPU 时代,这个方案的确是可行的,而且 ...
- java并发编程实战《四》互斥锁(下)
互斥锁(下):如何用一把锁保护多个资源? 一把锁可以保护多个资源,但是不能用多把锁来保护一个资源. 那如何保护多个资源? 当我们要保护多个资源时,首先要区分这些资源是否存在关联关系. 如下代码 ...
- Python并发编程05 /死锁现象、递归锁、信号量、GIL锁、计算密集型/IO密集型效率验证、进程池/线程池
Python并发编程05 /死锁现象.递归锁.信号量.GIL锁.计算密集型/IO密集型效率验证.进程池/线程池 目录 Python并发编程05 /死锁现象.递归锁.信号量.GIL锁.计算密集型/IO密 ...
- GIL与普通互斥锁区别,死锁现象,信号量,event事件,进程池与线程池,协程
GIL与普通互斥锁区别 GIL锁和互斥锁的异同点 相同: 都是为了解决解释器中多个线程资源竞争的问题 异: 1.互斥锁是Python代码层面的锁,解决Python程序中多线程共享资源的问题(线程数据共 ...
- GIL锁、进程池与线程池
1.什么是GIL? 官方解释: ''' In CPython, the global interpreter lock, or GIL, is a mutex that prevents multip ...
- GIL锁、进程池与线程池、同步异步
GIL锁定义 GIL锁:Global Interpreter Lock 全局解释器 本质上是一把互斥锁 官方解释: 在CPython中,这个全局解释器锁,也称为GIL,是一个互斥锁,防止多个线程在同 ...
- GIL解释锁及进程池和线程池
官方介绍 ''' 定义: In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple nati ...
- GIL全局解释器锁、死锁现象、python多线程的用处、进程池与线程池理论
昨日内容回顾 僵尸进程与孤儿进程 # 僵尸进程: 所有的进程在运行结束之后并不会立刻销毁(父进程需要获取该进程的资源) # 孤儿进程: 子进程正常运行 但是产生该子进程的父进程意外死亡 # 守护进程: ...
随机推荐
- 1293 - Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause
在数据库执行脚本文件时,执行到一半会遇到 这种问题: 出错处:2018-05-14 18:53:38 行号:712454 错误代码: 1293 - Incorrect table definitio ...
- Vuex模块:开启命名空间
模块开启命名空间后,享有独自的命名空间. { "模块1":{ state:{}, getters:{}, mutations:{}, actions:{} }, "模块2 ...
- 大于2T的硬盘怎么分区
使用parted工具: #yum install parted #parted /dev/sdb //选择要分的硬盘 GNUParted 2.3Using /dev/sdbWelcome to ...
- CTF中对web服务器各种提权姿势
在我们拿下服务器web服务往往只是低权限用户,对于内网渗透,我们往往需要root权限,Linux系统提权包括使用溢出漏洞已及利用系统配置文件. 提权前提: 1.拿到低权限shell 2.被入侵机器上有 ...
- JS 获取当前定位
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 并发-synchronized
线程并发-synchronized和Lock简单认知 前几天刚加深了线程的了解,期间在验证各种方法及多线程时遇到一些疑问,在高并发的情况下,怎么做才能保证程序还能按照我们预期的正常运行下去,这就是我们 ...
- Codeforces Round #225 (Div. 1) C. Propagating tree dfs序+ 树状数组或线段树
C. Propagating tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/383/p ...
- Redis分布式锁解决抢购问题
转:https://segmentfault.com/a/1190000011421467 废话不多说,首先分享一个业务场景-抢购.一个典型的高并发问题,所需的最关键字段就是库存,在高并发的情况下每次 ...
- Codeforces 1237E. Balanced Binary Search Trees
传送门 这一题是真的坑人,时间空间都在鼓励你用 $NTT$ 优化 $dp$...(但是我并不会 $NTT$) 看到题目然后考虑树形 $dp$ ,设 $f[i][0/1]$ 表示 $i$ 个节点的树,根 ...
- 垃圾分类API
###自从上月开始实行垃圾分类,整个上海人都已经“疯掉”了.那么,我们应该怎么识别什么是“垃圾”呢? 这里,我提供了并整理了几个api,其中包括图像识别,垃圾分类查找,根据关键字或者图片的内容来进行查 ...