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. 【笔记】vue和ssm开发接口联调跨域问题

    爬了两个小时的大坑 前端在github上拉了个vue项目,由于从来没正式学过vue,跨域这个问题一直困扰了很久. 目前暂时能用的解决方案(开发环境)就是: 前端在vue.config.js中加入代理. ...

  2. Opencv的线性滤波和非线性滤波

    线性滤波 :方框滤波   均值滤波  高斯滤波 非线性滤波: 中值滤波  双边滤波 这几个滤波都是起模糊作用 去除噪点 不废话了 下面是代码 #include <opencv2/opencv.h ...

  3. zabbix template

    1. template 是分层级的,所有很多修改需要到父级去修改,而且影响所有子级.

  4. MySQL锁会不会,你就差看一看

    数据库锁知识 不少人在开发的时候,应该很少会注意到这些锁的问题,也很少会给程序加锁(除了库存这些对数量准确性要求极高的情况下),即使我们不会这些锁知识,我们的程序在一般情况下还是可以跑得好好的.因为这 ...

  5. 【Luogu P5490】扫描线

    Luogu P5490 作为一道模板题让我卡了一个月…… 对于线段树+离散化新手而言这实在是太难了…… 有关离散化: 可以查看这一篇文章:https://www.jianshu.com/p/93476 ...

  6. day 23 面向对象中类的成员 和嵌套

    1.类的成员? 变量.方法.属性 class Foo: # 方法 def __init__(self,name): # 实例变量/字段 self.name = name # 方法 def func(s ...

  7. “达观杯”文本分类--baseline

    结合tfidf权重,对“达观杯”提供的文本,进行文本分类,作为baseline,后续改进均基于此. 1.比赛地址及数据来源 "达观杯"文本智能挑战赛 2.代码及解析 # -*- c ...

  8. 移动端App uni-app + mui 开发记录

    前言 uni-app uni-app是DCloud推出的终极跨平台解决方案,是一个使用Vue.js开发所有前端应用的框架,官网:https://uniapp.dcloud.io/ mui 号称最接近原 ...

  9. tcp协议传输方法&粘包问题

    socket实现客户端和服务端 tcp协议可以用socket模块实现服务端可客户端的交互 # 服务端 import socket #生成一个socket对象 soc = socket.socket(s ...

  10. OC中内存管理(转)

    OC内存管理 一.基本原理 (一)为什么要进行内存管理. 由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,这时需要回收一些不需要再继 ...