Python3 并发编程3
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的更多相关文章
- Python3 并发编程4
目录 Event事件 线程池与进程池 基本概念 使用方法 和信号量的区别 协程(coroutine) 基本概念 实现方式 多线程爬取梨视频 Event事件 用来控制线程的执行 e.isSet()查看对 ...
- Python3 并发编程小练习
实现基于TCP协议套接字,服务端实现接收客户端的连接并发 # server.py import socket from threading import Thread server = socket. ...
- Python3 并发编程2
目录 进程互斥锁 基本概念 互斥锁的使用 IPC 基本概念 队列 生产者消费者模型 基本概念 代码实现 线程 基本概念 创建线程 线程互斥锁 进程互斥锁 基本概念 临界资源: 一次仅允许一个进程使用的 ...
- Python3 并发编程1
目录 操作系统发展 穿孔卡片 批处理 多道技术(单核) 并发与并行 进程 程序与进程 进程调度 进程的三个状态 同步和异步 阻塞与非阻塞 僵尸进程与孤儿进程 守护进程 Python中的进程操作 Pro ...
- Python3 与 C# 并发编程之~ 进程篇
上次说了很多Linux下进程相关知识,这边不再复述,下面来说说Python的并发编程,如有错误欢迎提出- 如果遇到听不懂的可以看上一次的文章:https://www.cnblogs.com/dot ...
- Python3 与 C# 并发编程之~ 协程篇
3.协程篇¶ 去年微信公众号就陆陆续续发布了,我一直以为博客也汇总同步了,这几天有朋友说一直没找到,遂发现,的确是漏了,所以补上一篇 在线预览:https://github.lesschina.c ...
- Python3 与 C# 并发编程之~进程先导篇
在线预览:http://github.lesschina.com/python/base/concurrency/1.并发编程-进程先导篇.html Python3 与 C# 并发编程之- 进程篇 ...
- Python3 与 C# 并发编程之~ 线程篇
2.线程篇¶ 在线预览:https://github.lesschina.com/python/base/concurrency/3.并发编程-线程篇.html 示例代码:https://gith ...
- asyncio:python3未来并发编程主流、充满野心的模块
介绍 asyncio是Python在3.5中正式引入的标准库,这是Python未来的并发编程的主流,非常重要的一个模块.有一个web框架叫sanic,就是基于asyncio,语法和flask类似,使用 ...
随机推荐
- lufylegend.js教程(1)
1.图片元素如何缩小? 在LSprite类中,有两个属性:{scaleX,scaleY},这两个属性属于按比例缩放精灵对象,可以放大,可以缩小,注意这两个属性是在图片中心点位置开始缩放. 代码: Bo ...
- 通过javascript 执行环境理解她
古往今来最难的学的武功(javascript)算其一. 欲练此功必先自宫,愿少侠习的此功,笑傲江湖. 你将了解 执行栈(Execution stack) 执行上下文(Execution Context ...
- pat 1008 Elevator(20 分)
1008 Elevator(20 分) The highest building in our city has only one elevator. A request list is made u ...
- vue router路由跳转了,但是页面没有变(已解决)
小白学习 router.js:两个组件之间跳转 但是路由变了,页面没有改变的原因是因为app.vue里面没有router-view(很关键)
- python3 之 文件read方法(read、readline、readlines)
目录 一.read方法 二.readline方法 三.readlines方法 正文 python3中,读取文件有三种方法:read().readline().readlines(). 此三种方法,均支 ...
- Java File类常用方法及实例
创建:createNewFile()在指定位置创建一个空文件,成功就返回true,如果已存在就不创建,然后返回false. createTempFile(String prefix, String s ...
- Spring MVC使用ModelAndView进行重定向
1.Servlet重定向forward与redirect: 使用servlet重定向有两种方式,一种是forward,另一种就是redirect.forward是服务器内部重定向,客户端并不知道服务器 ...
- SpringSecurity框架下实现CSRF跨站攻击防御
一.什么是CSRF 很多朋友在学习Spring Security的时候,会将CORS(跨站资源共享)和CSRF(跨站请求伪造)弄混,以为二者是一回事.其实不是,先解释一下: CORS(跨站资源共享)是 ...
- 通过Javascript 创建POST提交, 无页面刷新下载
前端准备: //Download the template through "POST" request function getTargertContainer() { var ...
- HTML+Jquery实现多图片上传预览功能
HTML:使用input的onchange事件,它一改变就触发事件 <p id="p3"> <input name="File" onchan ...