GIL全局解释器锁

基本概念

  • global interpreter lock 全局解释器锁
  • GIL不是Python的特性, 是Cpython解释器的特性
  • GIL本质是一个互斥锁
  • 原因: Cpython解释器的内存管理不是线程安全的
  • 作用: 保证同一时间一个进程内只有一个线程在执行

多线程的作用

  • 计算密集型---多进程, GIL原因, 一个进程内的线程只能并发, 不能并行
  • I/O密集型---多线程, 开启线程与切换线程的速度要快于进程
# 计算密集型
import time
import os
from multiprocessing import Process
from threading import Thread # 计算密集型
def task1():
number = 0
for i in range(100000000):
number += 1
print('done!') if __name__ == '__main__':
start_time = time.time()
lis = []
for i in range(4):
# p = Process(target=task1) # 程序执行时间为16.711955785751343
t = Thread(target=task1) # 程序执行时间为26.467514038085938
lis.append(t)
t.start() for t in lis:
t.join() end_time = time.time()
print(f'程序执行时间为{end_time - start_time}')
# I/O密集型
import time
import os
from multiprocessing import Process
from threading import Thread # I/O密集型
def task2():
time.sleep(1) if __name__ == '__main__':
start_time = time.time()
lis = []
for i in range(20):
# p = Process(target=task2) # 程序执行时间为5.277301788330078
t = Thread(target=task2) # 程序执行时间为1.0040574073791504
lis.append(t)
t.start() for t in lis:
t.join() end_time = time.time()
print(f'程序执行时间为{end_time - start_time}')

死锁现象

  • 两个或者两个以上的线程在执行过程中, 因为争夺资源而产生的相互等待的状况
from threading import Thread, Lock
import time mutex_a = Lock()
mutex_b = Lock() class MyThread(Thread): def run(self):
self.func1()
self.func2() def func1(self):
mutex_a.acquire()
print(f'{self.name}拿到了锁a')
mutex_b.acquire()
print(f'{self.name}拿到了锁b')
mutex_b.release()
print(f'{self.name}释放了锁b')
mutex_a.release()
print(f'{self.name}释放了锁a') def func2(self):
mutex_b.acquire()
print(f'{self.name}拿到了锁b')
# I/O操作
time.sleep(1) mutex_a.acquire()
print(f'{self.name}拿到了锁a')
mutex_a.release()
print(f'{self.name}释放了锁a')
mutex_b.release()
print(f'{self.name}释放了锁b') if __name__ == '__main__':
for i in range(4):
t = MyThread()
t.start() '''
Thread-1拿到了锁a
Thread-1拿到了锁b
Thread-1释放了锁b
Thread-1释放了锁a
Thread-1拿到了锁b
Thread-2拿到了锁a
'''

递归锁

  • RLock 内部维护一个Lock和一个计数的counter, counter记录了acquire次数, 使得资源可以被多次请求
  • 直到一个线程所有的acquire都被release, 其他线程才能获取资源
from threading import Thread, RLock
import time mutex_a = mutex_b = RLock() class MyThread(Thread): def run(self):
self.func1()
self.func2() def func1(self):
mutex_a.acquire()
print(f'{self.name}拿到了锁a')
mutex_b.acquire()
print(f'{self.name}拿到了锁b')
mutex_b.release()
print(f'{self.name}释放了锁b')
mutex_a.release()
print(f'{self.name}释放了锁a') def func2(self):
mutex_b.acquire()
print(f'{self.name}拿到了锁b')
# I/O操作
time.sleep(3) mutex_a.acquire()
print(f'{self.name}拿到了锁a')
mutex_a.release()
print(f'{self.name}释放了锁a')
mutex_b.release()
print(f'{self.name}释放了锁b') if __name__ == '__main__':
for i in range(4):
t = MyThread()
t.start() '''
Thread-1拿到了锁a
Thread-1拿到了锁b
Thread-1释放了锁b
Thread-1释放了锁a
Thread-1拿到了锁b ---间隔了3秒--- Thread-1拿到了锁a
Thread-1释放了锁a
Thread-1释放了锁b
Thread-2拿到了锁a
Thread-2拿到了锁b
Thread-2释放了锁b
Thread-2释放了锁a
Thread-2拿到了锁b ---间隔了3秒--- Thread-2拿到了锁a
Thread-2释放了锁a
Thread-2释放了锁b
Thread-4拿到了锁a
Thread-4拿到了锁b
Thread-4释放了锁b
Thread-4释放了锁a
Thread-4拿到了锁b ---间隔了3秒--- Thread-4拿到了锁a
Thread-4释放了锁a
Thread-4释放了锁b
Thread-3拿到了锁a
Thread-3拿到了锁b
Thread-3释放了锁b
Thread-3释放了锁a
Thread-3拿到了锁b
Thread-3拿到了锁a
Thread-3释放了锁a
Thread-3释放了锁b
'''

信号量

  • from threading import Semaphore
  • 相当于多个互斥锁, 可以控制多个线程来访问数据 (可以控制访问资源的线程数量)
  • sm = Semaphore(5) 表示一次允许5个线程访问数据
  • acquire 一次, 括号内数字减一, release一次加一, 为0时限制其他线程访问
from threading import Thread, Semaphore, current_thread
import time # 一次允许5个线程访问数据
sm = Semaphore(5) def task():
sm.acquire()
print(f'{current_thread().name}已运行...')
time.sleep(3)
sm.release() if __name__ == '__main__':
for i in range(20):
t = Thread(target=task)
t.start() '''
Thread-1已运行...
Thread-2已运行...
Thread-3已运行...
Thread-4已运行...
Thread-5已运行... ---间隔了3秒--- Thread-6已运行...
Thread-7已运行...
Thread-8已运行...
Thread-9已运行...
Thread-10已运行... --间隔了3秒--- Thread-11已运行...
Thread-12已运行...
Thread-13已运行...
Thread-14已运行...
Thread-15已运行... ---间隔3秒--- Thread-17已运行...
Thread-16已运行...
Thread-18已运行...
Thread-19已运行...
Thread-20已运行...
'''

线程队列

  • queue.Queue() FIFO 先进先出
  • queque.LifoQueue() LIFO 后进先出
  • queque.PriorityQueue() 优先级, 根据元祖内的数据排序
import queue

# 先进先出 FIFO
q1 = queue.Queue()
q1.put(1)
q1.put(2)
q1.put(3) print(q1.get()) # 1 # 后进先出 LIFO
q2 = queue.LifoQueue()
q2.put(1)
q2.put(2)
q2.put(3)
print(q2.get()) # 3 # 优先级 按元祖内的数据排序
q3 = queue.PriorityQueue()
q3.put(('a',))
q3.put(('b',))
q3.put(('c',))
print(q3.get()) # ('a',)

Python3 并发编程3的更多相关文章

  1. Python3 并发编程4

    目录 Event事件 线程池与进程池 基本概念 使用方法 和信号量的区别 协程(coroutine) 基本概念 实现方式 多线程爬取梨视频 Event事件 用来控制线程的执行 e.isSet()查看对 ...

  2. Python3 并发编程小练习

    实现基于TCP协议套接字,服务端实现接收客户端的连接并发 # server.py import socket from threading import Thread server = socket. ...

  3. Python3 并发编程2

    目录 进程互斥锁 基本概念 互斥锁的使用 IPC 基本概念 队列 生产者消费者模型 基本概念 代码实现 线程 基本概念 创建线程 线程互斥锁 进程互斥锁 基本概念 临界资源: 一次仅允许一个进程使用的 ...

  4. Python3 并发编程1

    目录 操作系统发展 穿孔卡片 批处理 多道技术(单核) 并发与并行 进程 程序与进程 进程调度 进程的三个状态 同步和异步 阻塞与非阻塞 僵尸进程与孤儿进程 守护进程 Python中的进程操作 Pro ...

  5. Python3 与 C# 并发编程之~ 进程篇

      上次说了很多Linux下进程相关知识,这边不再复述,下面来说说Python的并发编程,如有错误欢迎提出- 如果遇到听不懂的可以看上一次的文章:https://www.cnblogs.com/dot ...

  6. Python3 与 C# 并发编程之~ 协程篇

      3.协程篇¶ 去年微信公众号就陆陆续续发布了,我一直以为博客也汇总同步了,这几天有朋友说一直没找到,遂发现,的确是漏了,所以补上一篇 在线预览:https://github.lesschina.c ...

  7. Python3 与 C# 并发编程之~进程先导篇

      在线预览:http://github.lesschina.com/python/base/concurrency/1.并发编程-进程先导篇.html Python3 与 C# 并发编程之- 进程篇 ...

  8. Python3 与 C# 并发编程之~ 线程篇

      2.线程篇¶ 在线预览:https://github.lesschina.com/python/base/concurrency/3.并发编程-线程篇.html 示例代码:https://gith ...

  9. asyncio:python3未来并发编程主流、充满野心的模块

    介绍 asyncio是Python在3.5中正式引入的标准库,这是Python未来的并发编程的主流,非常重要的一个模块.有一个web框架叫sanic,就是基于asyncio,语法和flask类似,使用 ...

随机推荐

  1. [java笔记] 最近学的一些笔记

    1.@Override的用法 2.父类的返回值类型的范围,与子类返回值类型的返回的大小关系: 3.子类方法的权限修饰符,与子类方法的权限修饰符: 4.如果p1是一个对象,p2也是个对象,那么代码p1= ...

  2. Java多态——代码示例

    刚开始看多态的文字定义时,总是不明白说的啥意思,看了一些示例代码后,总算知道了,其实也就是“多态”的字面意思. 如下: class A{ public void Out() { System.out. ...

  3. 021.掌握Pod-Pod调度策略

    一 Pod生命周期管理 1.1 Pod生命周期 Pod在整个生命周期过程中被系统定义了如下各种状态. 状态值 描述 Pending API Server已经创建该Pod,且Pod内还有一个或多个容器的 ...

  4. nyoj 57-6174问题(相邻元素判断问题)

    57-6174问题 内存限制:64MB 时间限制:1000ms Special Judge: No accepted:16 submit:31 题目描述: 假设你有一个各位数字互不相同的四位数,把所有 ...

  5. 总结:mysql的各种增删改查!

    (原创总结)分为数据库的增删改查,数据表(和字段)的增删改查,数据的增删改查 三部分!// 创建用户并授权 GRANT SELECT ON bodydb.user TO us@localhost ID ...

  6. tomcat-9.0.20缓存空间不足

    问题2:启动时候报这样的警告:警告 [main] org.apache.catalina.webresources.Cache.getResource 无法将位于[/WEB-INF/classes/t ...

  7. 使用TensorRT对caffe和pytorch onnx版本的mnist模型进行fp32和fp16 推理 | tensorrt fp32 fp16 tutorial with caffe pytorch minist model

    本文首发于个人博客https://kezunlin.me/post/bcdfb73c/,欢迎阅读最新内容! tensorrt fp32 fp16 tutorial with caffe pytorch ...

  8. cnpm镜像安装

    npm install -g cnpm --registry=https://registry.npm.taobao.org

  9. 修改Linux克隆的物理地址 和 IP地址

    实在不行就重新启动一下   才会改成 ech0 完成后文件配置环境变量 作为一个真正的程序员,首先应该尊重编程,热爱你所写下的程序,他是你的伙伴,而不是工具.

  10. Chapter 07-Basic statistics(Part3 correlations)

    这一部分使用R基础已安装包中的state.x77数据集.该数据集的数据是关于美国50个州在1977年对人口,收入,文盲率,平均寿命,谋杀率,高中毕业率统计所得. 1.关联的种类(types of co ...