GIL 线程池 进程池 同步 异步 阻塞 非阻塞
1.GIL
是一个全局解释器锁,是一种互斥锁
为什么需要GIL锁:因为一个python.exe进程中只有一份解释器,如果这个进程开启了多个线程都要执行代码
多线程之间要竞争解释器,一旦竞争就有可能出现问题
带来的问题:同一时间只有一个线程可以访问解释器
好处:保证了多线程的数据安全
thread_safe 线程安全的 多个线程同时访问也不会出问题
not thread_safe 非线程安全的多线程同时访问可能会出现问题(加锁)
默认情况下一个进程只有一个线程是不会出现问题的 但是不要忘记还有GC线程
一旦出现多线程就可能出问题,所以当初就简单粗暴的加上GIL锁
那么多线程是不是完全没有意义
由于有GIL的存在 即使有多个CUP 也不能真正的并行
有三个任务 三个任务要并发执行使效率最高
1.多进程
2.同一个进程下多线程
只有一个CUP
如果三个任务都要等待IO
如果是采用方案1:由于IO的时间较长 不仅不能提高效率反而无谓的增加了系统开销
方案2更好
有三个CUP
如果是采用方案1 并且三个任务都没有IO操作:开启三个进程并行的来执行 效率更高
如果是采用方案2 并且三个任务都没有IO操作:开三个线程 必须串行执行 所以效率比进程更低
应用程序分为两种
1.IO密集 IO操作较多 纯计算较少 采用多线程
from multiprocessing import Process
from threading import Thread, enumerate, current_thread
import time def task():
with open('db', 'rt', encoding='utf-8')as f:
f.read() if __name__ == '__main__':
start = time.time()
# for i in range(100):
# Thread(target=task).start()
#
# for t in enumerate():
# if t != current_thread():
# t.join()
ps = []
for i in range(100):
p = Process(target=task)
p.start()
for p in ps:
p.join()
print(time.time() - start)
2.计算密集型 计算操作较多 IO较少 采用多进程
from multiprocessing import Process
from threading import Thread, enumerate, current_thread
import time
import os def task():
a = 1
for i in range(10000000):
a += i if __name__ == '__main__':
start = time.time()
for i in range(10):
Thread(target=task).start() for t in enumerate():
if t != current_thread():
t.join()
# ps = []
# for i in range(10):
# p = Process(target=task)
# p.start()
# ps.append(p)
# for p in ps:
# p.join()
print(time.time() - start)
应用场景:
TCP程序 应该采用多线程
纯计算 列入人脸识别 语音识别等 采用多进程
什么情况需要自己加锁 当多个线程需要共享一个不属于解释器的资源时 必须要自己加
不用加锁的例子:多个线程要并发修改某个变量数据
2.线程池 进程池
from concurrent.futures import ThreadPoolExecutor
import time
import threading def task():
print('running.......') pool = ThreadPoolExecutor(3)
pool.submit(task)
pool.submit(task)
pool.submit(task)
pool.submit(task)
print(threading.active_count())
print(threading.enumerate()) time.sleep(3)
print(threading.active_count())
print(threading.enumerate())
池就是容器
服务器不能无限的开线程,所以需要对线程数量加以控制,
线程池就帮我们封装了线程数量的控制 以及线程的创建 以及线程的创建 销毁 任务的分配
使用方法都一样
线程池再创建时不会立即开启线程
等到提交任务时 如果没有空闲线程 并且已存在的线程数量 小于最大值 开个新的
线程开启以后就不会再关闭了 直到进程全部关闭
3.同步 异步 阻塞 非阻塞
阻塞:
程序运行过程中遇到IO操作 无法继续
非阻塞:
程序正在运行中,并且没有遇到IO,即使遇到IO也不会阻塞,CPU不会切走
指的是程序的执行的状态
同步:
在发起任务后必须在原地等待 任务执行完毕 才能继续往下执行
def task():
for i in range(100000000):
pass print('start')
task()
print('over')
异步:
在发起任务后立即继续往下执行,不需要等待任务的执行结果
# def task():
# for i in range(100000000):
# pass
#
#
# print('start')
# task()
# print('over')
from concurrent.futures import ThreadPoolExecutor pool = ThreadPoolExecutor()
import time def task(num):
time.sleep(0.5)
print('run...')
return num ** 2 ress = []
for i in range(1, 11):
res = pool.submit(task, i)
# res.result() # 该函数是阻塞函数 会一直等到任务执行完毕 导致程序串行执行
ress.append(res) # 保证 当我们要获取的时候 所有任务都已经执行完毕
pool.shutdown(wait=True) # 该函数也是阻塞函数
# 等到全部完成在获取结果
for i in ress:
print(i.result()) print('over')
指的是发起任务的方式
异步效率高于同步
发起异步任务的方式 就是线程和进程
同步和阻塞是完全不同的
阻塞一定是CUP已经切走了
同步虽然也会卡住 但是CUP没切走 还在你的进程中
并发的TCP
import socket from concurrent.futures import ProcessPoolExecutor
from multiprocessing import Process def task(client):
while True:
data = client.recv(1024)
print(data.decode('utf-8'))
client.send(data.upper()) if __name__ == '__main__':
server = socket.socket()
server.bind(('127.0.0.1', 8888))
server.listen()
# 创建一个进程池
pool = ProcessPoolExecutor(3)
while True:
client, address = server.accept() # 三次握手
# 控制链接数量 得用连接池
# 开启一个进程来处理这个连接
# t=Process(target=task,args=(client,))
# t.start()
# 现在将任务交到进程池中
pool.submit(task, client)
server进程池
import socket client = socket.socket()
client.connect(('127.0.0.1', 8888))
while True:
msg = input(">>>:").strip()
if not msg:
continue
client.send(msg.encode('utf-8'))
print(client.recv(1024).decode('utf-8'))
client
import socket from concurrent.futures import ThreadPoolExecutor
from threading import Thread def task(client):
while True:
data = client.recv(1024)
print(data.decode('utf-8'))
client.send(data.upper()) if __name__ == '__main__':
server = socket.socket()
server.bind(('127.0.0.1', 8888))
server.listen()
# 创建一个线程池
pool = ThreadPoolExecutor(3)
while True:
client, address = server.accept() # 三次握手
# 控制链接数量 得用连接池
# 开启一个线程来处理这个连接
# t=Process(target=task,args=(client,))
# t.start()
# 现在将任务交到线程池中
pool.submit(task, client)
server线程池
GIL 线程池 进程池 同步 异步 阻塞 非阻塞的更多相关文章
- tornado 学习笔记4 异步以及非阻塞的I/O
Read-time(实时)的网站需要针对每个用户保持长时间的连接.在传统的同步网站服务中,通常针对每个用户开启来一个线程来实现,但是这样做非常昂贵. 为了使并发连接的成本最小化,Tornada使用单个 ...
- GIL 线程池 进程池 同步 异步
1.GIL(理论 重点)2.线程池 进程池3.同步 异步 GIL 是一个全局解释器锁,是一个互斥锁 为了防止竞争解释器资源而产生的 为何需要gil:因为一个python.exe进程中只有一份解释器,如 ...
- python GIL锁、进程池与线程池、同步异步
一.GIL全局解释器锁 全局解释器锁 在CPython中,全局解释器锁(GIL)是一个互斥锁,它可以防止多个本机线程同时执行Python代码.之所以需要这个锁,主要是因为CPython的内存管理不是线 ...
- GIL锁、进程池与线程池、同步异步
GIL锁定义 GIL锁:Global Interpreter Lock 全局解释器 本质上是一把互斥锁 官方解释: 在CPython中,这个全局解释器锁,也称为GIL,是一个互斥锁,防止多个线程在同 ...
- Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就绪,挂起,运行) ,***协程概念,yield模拟并发(有缺陷),Greenlet模块(手动切换),Gevent(协程并发)
Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就 ...
- python 之 并发编程(进程池与线程池、同步异步阻塞非阻塞、线程queue)
9.11 进程池与线程池 池子使用来限制并发的任务数目,限制我们的计算机在一个自己可承受的范围内去并发地执行任务 池子内什么时候装进程:并发的任务属于计算密集型 池子内什么时候装线程:并发的任务属于I ...
- {Python之进程} 背景知识 什么是进程 进程调度 并发与并行 同步\异步\阻塞\非阻塞 进程的创建与结束 multiprocess模块 进程池和mutiprocess.Poll
Python之进程 进程 本节目录 一 背景知识 二 什么是进程 三 进程调度 四 并发与并行 五 同步\异步\阻塞\非阻塞 六 进程的创建与结束 七 multiprocess模块 八 进程池和mut ...
- 并发编程 - 线程 - 1.线程queue/2.线程池进程池/3.异步调用与回调机制
1.线程queue :会有锁 q=queue.Queue(3) q.get() q.put() 先进先出 队列后进先出 堆栈优先级队列 """先进先出 队列"& ...
- 进程| 线程 | 阻塞 | 阻塞&非阻塞 和 同步&异步
阻塞&非阻塞 阻塞IO 调用之后一定要等到系统内核完成所有的操作之后才结束,因此它的缺点:CPU等待IO,处理能力得不到充分利用. 非阻塞IO 为了解决阻塞IO带来的一些问题,内核提供了非阻塞 ...
随机推荐
- 修改LINUX ROOT密码
Connecting to 10.10.70.22:22... Connection established. To escape to local shell, press 'Ctrl+Alt+]' ...
- Alert---点击拍照弹出对话框
/** * 照片对话框 *AlertDialog */ private void PhotoDialog() { AlertDialog.Builder builder = new Builder(m ...
- VS2012新建网站出现(1)的解决方案
1.用记事本打开以下文件: D:\Users\lyn\Documents\IISExpress\config\applicationhost.config 2.删除sites结点下的所有site结点:
- Ros问题汇总
1.ImportError: No module named beginner_tutorials.srv 解决: cd ~/catkin_ws $ source devel/setup.bash $ ...
- ZROI2018普转提day2t2
传送门 分析 我们发现2R+C实际就相当于R行C列的子集的个数.因此我们可以将所有集合的子集个数转换为每个集合属于的集合的个数.所以我们可以求出: 这个式子的意义为对于选i行j列的情况的所有方案乘上i ...
- Luogu 3911 最小公倍数之和
感觉自己被早上的名校协作体和下午的数学题虐哭了,每天为自己的菜发愁…… 发现$a_{i}$很小,开一个桶记一下每个数 出现的个数,设$c_{i} = \sum_{j = 1}^{n}(a_{j} == ...
- Bulma 中的媒体查询
在 Bulma 中将设备分为 6 类:手机.平板.触屏设备.桌面.宽屏和大屏.提供了四个阈值. // sass/utilities/variables.sass $tablet: 769px !def ...
- .net中值类型、引用类型理解的c#代码示例
下面是以前在公司的时候给别人讲解值类型.引用类型时创建的c#代码示例,从实际使用时的角度出发,对于初学者还是很有帮助的.这里并没有深入讲解值类型包含引用类型成员时(如struct)在内存中的存放情况等 ...
- OpenStack部署的简单模型
记录下看到的openstack部署的简单模型,方便自己以后定位问题 规划网络部署节点为一个controller节点(包含网络节点),两个compute节点.controller节点有3个网卡,分别为e ...
- 【bzoj3209】: 花神的数论题 数论-DP
[bzoj3209]: 花神的数论题 首先二进制数中1的个数最多就是64个 设所有<=n的数里二进制中1的个数为i的有a[i]个 那么答案就是 然后快速幂 求a[i]可以用DP 设在二进制中从 ...