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类似,使用 ...
随机推荐
- php如何在mysql里批量插入数据
假如说我有这样一个表,我想往这个表里面插入大量数据 CREATE TABLE IF NOT EXISTS `user_info` ( `id` int(11) NOT NULL AUTO_INCREM ...
- suseoj 1211: 子集和问题 (dfs)
1211: 子集和问题 时间限制: 1 Sec 内存限制: 128 MB提交: 2 解决: 2[提交][状态][讨论版][命题人:liyuansong] 题目描述 子集和问题的一个实例为<S ...
- 记录工作遇到的死锁问题(Lock wait timeout exceeded; try restarting transaction)
1.问题背景 刚来新公司不久,对业务还不太熟悉,所以领导先安排我维护原有系统.大概介绍下项目背景,项目分为核心业务部分在项目A中,与第三方交互的业务在项目B中,前端发起请求调用A项目接口,并在A项目中 ...
- linux内核的tiny rcu, tree rcu
kernel中有两个rcu的实现,一个是tiny rcu,另一个是tree rcu.这两种rcu的前身都是classic rcu.如果要阅读classic rcu的实现代码,必须找kernel 2.6 ...
- opencv 3 core组件进阶(1 访问图像中的像素)
访问图像像素的三类方法 ·方法一 指针访问:C操作符[ ]; ·方法二 迭代器iterator; ·方法三 动态地址计算. #include <opencv2/core/core.hpp> ...
- 在linux系统下进行pip升级注意事项
今天鼓捣爬虫的时候需要用pip安装beautifulsoup4,但是出现了错误,说我的pip版本太低,需要升级一下.刚开始我用了下面这段代码: pip install --upgrade pip 显示 ...
- 2019-10-29:渗透测试,基础学习,sqlmap文件读取,写入,dnslog盲注作用,mssql手工注入,笔记
sqlmap参数--file-read,从数据库服务器中读取文件--file-write,--file-dest,把文件上传到数据库服务器中 dnslog平台的学习和它在盲注中的应用1,判断注入点2, ...
- /etc/security/limits.conf配置文件详解
这个文件主要是用来限制用户对系统资源的使用.是/lib64/security/pam_limits.so模块对应的/etc/serurity/pam_limits的配置文件. # /etc/secur ...
- scrapy知识补充--scrapy shell 及Spider
什么是scrapy shell? Scrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试xpath或css表达是,来查看他们的工作方式,方便爬取页面中的数据 ...
- c 程序之 最大公约数 和 最小公倍数
1.最大公约数 30 10 -> 10 #include<stdio.h> /* 求最大公约数 辗转相减法 36 --16 4 */ int main(){ int a, ...